Ben*_*ler 15 c function-pointers qsort
我正在编写一个函数,它接收一个指向比较函数的指针和一个数组,MyStructs并且应该根据比较函数对数组进行排序:
void myStructSort(
struct MyStruct *arr,
int size,
int (*comp)(const struct MyStruct *, const struct MyStruct *)) {
qsort(arr, size, sizeof(struct MyStruct), comp);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不会编译,因为qsort期望比较器接收void *参数而不是const struct MyStruct *.我想到了几个不好的解决方案,并想知道正确的解决方案是什么.
选项1
铸造comp到int (*)(const void *, const void*).这编译但是未定义的行为(参见这个问题).
选项2
创建一个全局变量int (*global_comp)(const struct MyStruct *, const struct MyStruct *),并设置global_comp=comp里面myStructSort.然后创建一个函数:
int delegatingComp(const void *a, const void *b) {
return globalComp((const struct MyStruct *)a, (const struct MyStruct *)b);
}
Run Code Online (Sandbox Code Playgroud)
而在myStructSort通话qsort(arr, size, sizeof(struct MyStruct), delegatingComp).这个问题是icky全局变量.
选项3
重新实现qsort.这是功能安全但非常糟糕的做法.
有没有神奇的完美第四选择?
编辑
我无法更改API,myStructSort我正在编译我的代码使用gcc c99 -Wall -Wextra -Wvla.
Kla*_*äck 10
选项2打破了线程安全性,所以我不会选择那个.
你指出,选项3是完全错误的.没有理由重新实施快速排序并可能犯错误.
选项1是UB,但它适用于任何理智的编译器.如果选择此选项,请务必添加注释.
我还会考虑:
选项4.重新设计完全myStructSort接受int (*)(const void *, const void*)或废弃的界面并qsort直接致电.基本上把它发回给architecht,因为他做了一个糟糕的设计选择.
以下方法仅适用于gcc.它是gnu扩展的一部分.进一步请参考https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Nested-Functions.html#Nested-Functions
首先让我们确保原型qsort是这样的形式:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
Run Code Online (Sandbox Code Playgroud)
然后你可以:
void myStructSort(
struct MyStruct *arr,
int size,
int (*comp)(const struct MyStruct *, const struct MyStruct *)) {
int comparator(const void * a, const void *b) {
return comp((const struct MyStruct *)a, (const struct MyStruct *)b);
}
qsort(arr, size, sizeof *arr, comparator);
}
Run Code Online (Sandbox Code Playgroud)
但是,再次,因为它使用gnu扩展,不要指望太多的可移植性.
关于你的评论:对于现代gcc,gnu标准是默认标准而不是iso标准.具体而言,最新gcc应该使用gnu11标准.老年人正在使用gnu89.所以,我不知道你的命令行参数,但如果-std没有设置,这将工作.
以下是一个例子info gcc,以防链接死亡.它显示了嵌套函数的类似闭包的用法:
bar (int *array, int offset, int size)
{
int access (int *array, int index)
{ return array[index + offset]; }
int i;
/* ... */
for (i = 0; i < size; i++)
/* ... */ access (array, i) /* ... */
}
Run Code Online (Sandbox Code Playgroud)