C语言中的可移植嵌套函数 [英] Portable nested functions in C
问题描述
是否可以使用嵌套函数/块编写可移植的C代码?
Is it possible to write portable C code using nested functions/blocks?
我了解gcc仅支持嵌套函数作为非标准扩展,而clang仅支持块-但是有没有办法编写将代码与MACROS一起使用都可以在两者上编译的代码?
I understand that gcc only supports nested functions as an non-standard extension, and clang only supports blocks - but is there a way to write code that will compile on both using standard C with MACROS?
如果不可能-最好的解决方法是什么?例如,如何实现以下带有参数的可移植版本? GCC中的琐碎示例:
If it is not possible - what is the best work around? As an example, how would one implement a portable version of the following sort that takes a parameter? Trivial example in 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来组合类似的示例.理想情况下,解决方案应该是线程安全的(因此请避免使用全局变量).
A similar example could be put together using Blocks in Clang. Ideally the solution should be thread-safe (so avoid global variables).
编辑:为清楚起见,假设标准"表示C99.上面是一个简单的例子.我需要的是一种C99方法,该方法需要一些参数.在这里,它只是使用char作为布尔值,但是我正在寻找一个采用多个整数等的解决方案.如果没有全局变量,这似乎是不可能的.
For clarity, lets assume "standard" means C99. The above is a trivial example. What I'm after is a C99 approach to a sort that requires some parameters. Here it just uses a char as a boolean, but I'm after a solution that would take multiple integers etc. It looks like this might not be possible without global variables.
我意识到,将void指针与函数指针一起传递可以使您完成嵌套函数可以完成的所有工作.感谢@Quuxplusone建议qsort_r
和qsort_s
.我试图将便携式包装器放在qsort_r
和qsort_s
上.它需要一个比较器函数和一个空指针来存储状态,从而消除了复杂函数排序算法对嵌套函数的依赖,因此您可以同时使用GCC和Clang进行编译.
Edit 2: I realised that passing a void pointer along with a function pointer enables you to do everything that can be done with nested functions. Thanks to @Quuxplusone for suggesting qsort_r
and qsort_s
. I've tried to put together a portable wrapper on qsort_r
and qsort_s
. It takes a comparator function and a void pointer to store state in, thus removing the dependency on nested functions for intricate sorting algorithms -- so you can compile with both GCC and 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
}
注意:我尚未在许多平台上对此进行测试,因此,如果您看到错误,请告诉我/这在您的计算机上不起作用.
Note: I haven't tested this on many platforms, so please let me know if you see a bug / this doesn't work on your machine.
作为用法示例,我实现了与所选答案相同的排序方式:
As an example of usage, I've implemented the same sort as in the chosen answer:
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);
推荐答案
Following the suggestion by @Kirilenko here, I've come up with a solution using global variables and a mutex to pass parameters to a sort comparator function. This approach is thread-safe, can do everything achieved with nested functions and should be portable between compilers.
此示例对整数列表进行排序,但将给定区域的排序反转.
This example sorts a list of integers, but inverts the sort for a given region.
// 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语言中的可移植嵌套函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!