C中的可移植嵌套函数

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

我知道gcc只支持嵌套函数作为非标准扩展,而clang只支持块 – 但是有没有办法编写可以使用标准C和MACROS进行编译的代码?

如果不可能 – 最好的工作是什么? 举个例子,如何实现一个带参数的以下类型的可移植版本? 海湾合作委员会的简单例子:

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作为布尔值,但我正在使用一个可以采用多个整数等的解决方案。看起来如果没有全局变量,这可能是不可能的。

编辑2:我意识到传递一个void指针和一个函数指针可以让你做所有可以用嵌套函数完成的事情。 感谢@Quuxplusone建议qsort_rqsort_s 。 我试图在qsort_rqsort_sqsort_r一个便携包装器。 它需要一个比较器函数和一个用于存储状态的void指针,从而消除了对复杂排序算法的嵌套函数的依赖性 – 因此您可以使用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 } 

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

作为一个使用示例,我已经实现了与所选答案相同的排序:

 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_end || *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标准不允许嵌套函数。
宏在这里对你没有多大帮助,因为它们由预处理器进行评估,编译器仍会看到嵌套函数的代码并标记错误。

根据@Kirilenko的建议,我提出了一个使用全局变量和互斥锁将参数传递给排序比较器函数的解决方案。 这种方法是线程安全的,可以使用嵌套函数完成所有事情,并且应该可以在编译器之间移植。

此示例对整数列表进行排序,但反转给定区域的排序。

 // define lock for sort parameters pthread_mutex_t lock; // Parameters used in sort funciton - invert region (inclusive) int invert_start, invert_end; // Comparitor that uses global variables (invert_start, invert_end) as paramaters int cmp_func(const void *a, const void *b) { const int aa = *(const int*)a; const int bb = *(const int*)b; if(aa < invert_start || aa > invert_end || bb < invert_start || bb > invert_end) { return aa - bb; } else { return bb - aa; } } void sort_things(int* arr, int arr_len, int inv_start, int inv_end) { // Mutex lock pthread_mutex_lock(&lock); // Set params invert_start = inv_start; invert_end = inv_end; // do sort qsort(arr, arr_len, sizeof(*arr), &cmp_func); // Mutex free pthread_mutex_unlock(&lock); } 

示例结果:

 input: 1 5 28 4 3 2 10 20 18 25 21 29 34 35 14 100 27 19 invert_start = 20, invert_end = 30 output: 1 2 3 4 5 10 14 18 19 29 28 27 25 21 20 34 35 100 

嵌套函数不在C标准中,但它是gcc扩展(当标志-fnested-functions被激活时)。 此外,您可以使用静态函数( cmp_func )和额外参数( reverse )来执行相同的操作。

为什么要去嵌套函数和全局变量的麻烦? 100%便携式(甚至是K&R)解决方案只是使用两种不同的function,一种是按常规顺序排序,另一种是反向排序,然后将其称为

 qsort(list, 8, sizeof(int), reverse ? cmp_func_reverse : cmp_func); 

注意:不需要使用&函数的地址。