我想使用C的qsort()函数对每个具有不同类型的数组进行排序,如下所示:
int a[] = {1, 2, 3};
const char *b[] = {"foo", "bar", "bas"};
my_defined_type_t *c[100]; for (i=0; i<100; i++) { fill(c[i]); }
是否有必要为每种类型编写比较函数,如intComparator(),stringComparitor(),myDefinedTypeComparitor(),并依次对每个比较函数调用qsort,或者可以在C中完成这样的事情:
int myGrandUnifiedComparisonFunction(const void* a, const void* b) {
if *a, *b are integers: intComparatorCode;
if *a, *b are strings: stringComparitorCode;
if *a, *b are my_defined_type_t's: myDefinedTypeComparitorCode;
/* etc. */
}
答案 0 :(得分:3)
需要考虑两个问题:
1)信息问题
你的比较函数获得两个void指针。这只是一些可能意味着什么的模式。 C不会将任何信息附加到例如浮点数或字符指针上,因此如果您事先不知道,则无法判断某些数据是否是其中一个。
也就是说,您可以自己附加这些信息,方法是将数据包含在一个结构中,并附上一个枚举值,告诉您内部的内容。但从技术上讲,你不会比较浮点数或char指针,而是包装浮点数和包裹的char指针。类似的东西:
enum { Float, String, MyType } typ;
typedef struct {
typ t;
union {
float f;
char *s;
myType mt;
} wrappedData;
然后你可以写一个比较wrappedData *
的函数。
这就是每种动态语言的作用。
然后,即使你的大统一功能仍然需要适当地比较它们,也就是说,每种类型都不同,所以你不会获得太多。相反,你可以将逻辑组合成一个并不真正属于一个的函数。
2)效率问题
虽然这可能不会打扰你,但是每次比较操作都会解开一个指针并检查它的类型,这可能会大大增加你的运行时间。
<强>结论:强>
你必须采取某种方式包装你的数据,这是一个可疑的优势和显着的劣势(效率)。不要这样做。
答案 1 :(得分:2)
C没有introspection,因此无法知道void*
指向的是什么类型。
每种类型需要一个比较函数,并且必须使用正确的回调调用qsort
。
答案 2 :(得分:1)
你的想法
int myGrandUnifiedComparisonFunction(const void* a, const void* b) {
if *a, *b are integers: intComparatorCode;
if *a, *b are strings: stringComparitorCode;
if *a, *b are my_defined_type_t's: myDefinedTypeComparitorCode;
/* etc. */
}
非常好。你有没有尝试过它?
问题在于无法在C或C ++中实现它。无法确定void*
指向的变量类型。
答案 3 :(得分:0)
不,你不能拥有泛型函数,因为类型现在在运行时在C中传递(与面向对象语言不同)。必须在编译时知道该类型。
因此,您需要拥有一个知道如何比较每种类型的函数并告诉qsort
该函数。
答案 4 :(得分:0)
我猜你可以,如果你以某种方式神奇地知道类型,但为什么要打扰?此外,您还可以传入大小,因此您需要在2个地方进行检查。
不确定这有什么好处。