使用嵌套函数/块编写可移植的C代码是否可能?
我知道gcc只支持嵌套函数作为非标准扩展,而clang只支持块 - 但是是否有一种方法可以使用MACROS编写能够在两者上编译的标准C代码?
如果不可能-最佳解决方法是什么?例如,如何实现接受参数的以下排序的可移植版本?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中的块可以组合一个类似的示例。理想情况下,解决方案应该是线程安全的(因此避免使用全局变量)。
编辑:为了清晰起见,假设“标准”表示C99。上面是一个微不足道的例子。我想要的是一种需要一些参数的排序的C99方法。这里只使用一个char作为布尔值,但我想要一个可以使用多个整数等的解决方案。看起来这可能没有全局变量是不可能的。
编辑2:我意识到,通过传递void指针和函数指针,您可以执行可以使用嵌套函数完成的所有操作。感谢@Quuxplusone建议的qsort_r和qsort_s。我尝试组合了一个便携式包装器,用于qsort_r和qsort_s。它接受比较器函数和一个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
}
注意:我还没有在许多平台上测试过这个,所以如果您在您的设备上发现了错误/无法工作,请让我知道。
举个例子,我已经实现了与选择的答案相同的排序方法。
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);
cmp_func
函数应该和你展示的一样好。 - Curious