是否可以使用嵌套函数/块编写可移植的C代码?
我知道gcc只支持嵌套函数作为一个非标准的扩展,而clang只支持块,但是有什么方法可以用标准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方法。这里它只使用一个字符作为布尔值,但我想要的是一个需要多个整数等的解决方案。看起来,如果没有全局变量,这可能是不可能的。
编辑2:我意识到,通过传递一个空指针和一个函数指针,您可以完成所有可以使用嵌套函数完成的工作。感谢@Quuxplusone建议qsort_r和qsort_s。我试图在qsort_r和qsort_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);发布于 2012-09-05 14:52:00
按照@Kirilenko here的建议,我提出了一个使用全局变量和互斥变量将参数传递给排序比较器函数的解决方案。这种方法是线程安全的,可以用嵌套函数完成任何事情,并且应该在编译器之间可移植。
此示例对整数列表进行排序,但反转给定区域的排序。
// 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发布于 2013-02-08 21:28:45
只是为了好玩(并回答原来的问题),是的,完全可以用符合标准的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能用预处理器来处理这么多宏的重量。
发布于 2012-08-31 11:57:40
没有用C编写嵌套函数的可移植方法,仅仅因为C标准不允许嵌套函数。
宏在这里对您帮助不大,因为它们是由预处理器计算的,编译器仍然会看到嵌套函数和标记错误的代码。
https://stackoverflow.com/questions/12214867
复制相似问题