c - C 中的可移植嵌套函数

标签 c gcc clang nested-function

是否可以使用嵌套函数/ block 编写可移植的 C 代码?

我知道 gcc 仅支持作为非标准扩展的嵌套函数,而 clang 仅支持 block - 但是有没有一种方法可以使用标准 C 和 MACROS 编写可以在两者上编译的代码?

如果不可能 - 最好的解决方法是什么?例如,如何实现以下带有参数的可移植版本? GCC 中的简单示例:

int main(int argc, char*[] argv)
{
  char reverse = 0;

  int cmp_func(const void *a, const void *b)
  {
    const int* aa = (const int)a;
    const int* bb = (const int)b;
    return (reverse) ? aa - bb : bb - aa;
  }

  int list[8] = {1,2,3,4,5,20,100,200};
  qsort(list, 8, sizeof(int), &cmp_func);
}

可以使用 Clang 中的 Blocks 将类似的示例放在一起。理想情况下,解决方案应该是线程安全的(因此避免使用全局变量)。

编辑:为清楚起见,假设“标准”是指 C99。以上是一个简单的例子。我所追求的是一种需要一些参数的 C99 方法。这里它只是使用一个 char 作为 bool 值,但我正在寻找一个需要多个整数等的解决方案。看起来如果没有全局变量,这可能是不可能的。

编辑 2: 我意识到传递一个 void 指针和一个函数指针可以让您完成嵌套函数可以完成的所有事情。感谢@Quuxplusone 建议 qsort_rqsort_s。我试图在 qsort_rqsort_s 上放置一个可移植的包装器。它需要一个比较器函数和一个空指针来存储状态,从而消除了对复杂排序算法的嵌套函数的依赖——因此您可以同时使用 GCC 和 Clang 进行编译。

typedef struct
{
  void *arg;
  int (*compar)(const void *a1, const void *a2, void *aarg);
} SortStruct;

int cmp_switch(void *s, const void *aa, const void *bb)
{
  SortStruct *ss = (SortStruct*)s;
  return (ss->compar)(aa, bb, ss->arg);
}

void sort_r(void *base, size_t nel, size_t width,
            int (*compar)(const void *a1, const void *a2, void *aarg), void *arg)
{
  #if (defined _GNU_SOURCE || defined __GNU__ || defined __linux__)

    qsort_r(base, nel, width, compar, arg);

  #elif (defined __APPLE__ || defined __MACH__ || defined __DARWIN__ || \
         defined __FREEBSD__ || defined __BSD__ || \
         defined OpenBSD3_1 || defined OpenBSD3_9)

    SortStruct tmp = {arg, compar};
    qsort_r(base, nel, width, &tmp, &cmp_switch);

  #elif (defined _WIN32 || defined _WIN64 || defined __WINDOWS__)

    SortStruct tmp = {arg, compar};
    qsort_s(*base, nel, width, &cmp_switch, &tmp);

  #else
    #error Cannot detect operating system
  #endif
}

注意:我没有在很多平台上测试过这个,所以如果你发现一个错误/这在你的机器上不起作用,请告诉我。

作为用法示例,我实现了与所选答案中相同的排序:

int sort_r_cmp(const void *aa, const void *bb, void *arg)
{
  const int *a = aa, *b = bb, *p = arg;
  int cmp = *a - *b;
  int inv_start = p[0], inv_end = p[1];
  char norm = (*a < inv_start || *a > inv_end || *b < inv_start || *b > inv_end);

  return norm ? cmp : -cmp;
}

int arr[18] = {1, 5, 28, 4, 3, 2, 10, 20, 18, 25, 21, 29, 34, 35, 14, 100, 27, 19};
int p[] = {20, 30};
sort_r(arr, 18, sizeof(int), sort_r_cmp, p);

最佳答案

只是为了好玩(并回答原始问题),是的,完全可以使用宏系统在符合标准的 C99 中编写嵌套函数来“解开”代码的嵌套版本。这是一种可能的实现方式:https://github.com/Leushenko/C99-Lambda

有了它,你就可以像这样写可憎的东西了:

typedef int(* fptr)(int);
func(fptr, someFunc, (void) {
    return fn(int, (int a), {
        fptr f = fn(int, (int b), { return b * 6; });
        return a * f(a + 1);
    });
})

不过,让我们非常清楚一些事情:这是用 C 语言编写此类代码的绝对最糟糕的方式。如果您发现自己处于这样的境地:居然要用宏库写这样的代码,辞掉程序员的工作去当农民。在生产中使用它,你的同事可能会在你睡梦中杀了你。

此外,有趣的是,尽管它在技术上符合标准,但唯一具有可以处理如此多宏的绝对重量的预处理器的编译器是 GCC 和 Clang。

关于c - C 中的可移植嵌套函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12214867/

相关文章:

c - 如何在 32 位架构中将 64 位 unsigned long long 分配给 32 位结构

使用c中的结构进行复杂 vector 加法

c - C Segmentation Fault中的二叉搜索树

linux - 什么时候应该重新编译手动编译的程序?

c++ - Clang、LLVM 和 g++

python - 我可以用 C 重写昂贵的 pygame 函数吗?

c - in - gcc 内联汇编的操作数类型不匹配

linux - 执行附加在可执行文件末尾的机器代码

c++ - atexit() 与独立的 CLang 未定义

无法为 enp4s0 上的套接字设置 SO_BINDTODEVICE