2009-07-02 60 views
4

只是我还是这个代码Programming Pearls是错误的(快速排序要2个const的空隙,不是吗?)如果是这样,我的解决方案吗?道歉,只是学习...错误qsort函数编程珍珠?

int wordncmp(char *p, char* q) 
{ int n = k; 
    for (; *p == *q; p++, q++) 
     if (*p == 0 && --n == 0) 
      return 0; 
    return *p - *q; 
} 

int sortcmp(char **p, char **q) 
{ return wordncmp(*p, *q); 
} 
... 

qsort(word, nword, sizeof(word[0]), sortcmp); 

这是一个解决方案吗?

int sortcmp(const void *p, const void *q) 
{ return wordncmp(* (char * const *) p, * (char * const *) q); 
} 

回答

7

第一个代码示例可能适用于几乎所有的编译器和CPU;然而,如果你遵循C标准的话,这在技术上是不确定的行为。

正如你所说,qsort()的最后一个参数是一个函数指针,它带有const void*类型的两个参数。 sortcmp有不同的论点。你的编译器应该让你一不兼容类型签名什么的警告。在任何情况下,演员都是从一种类型的功能执行到另一种类型的功能。

C标准规定,你可以投函数指针与不同类型的其它的函数指针,但你不能解引用和调用铸造的函数指针。不过,如果你再投的函数指针回到原来的类型,然后调用已定义的行为 - 它调用原来的功能。

既然你从int (*)(char**, char**)强制转换为int (*)(const void*, const void*),然后最终qsort()被调用的比较器功能而无需进行转换回int (*)(char**, char**),这是不确定的行为。

但是,由于实际上在所有体系结构中,char **const void*都以相同的方式表示,函数调用几乎总能正常工作。

如果您想获取定义的行为,您必须确保您的比较器函数具有正确的类型签名,然后您可以将参数转换为正确的类型。您的解决方案完全正确,并且不违反那里的C标准。干得好上const -correctness - 很多人不明白到底是什么char * const *手段。

你也应该做的const char*wordncmp()带参数,因为你不修改参数。

附注:您也可以在技术上不是一个函数指针转换为数据指针(例如void*),反之亦然。该标准允许函数指针和数据指针具有不同的大小。即使它在您的计算机上正常工作,也不能保证始终有效。

+0

这个标准实际上不能保证'char *`和`void *`具有相同的表示吗?我同意UB仍然使用错误的函数指针类型进行调用,但我不相信这些参数的表示是问题。问题在于,病态实现可以使用不同的调用约定来传递`void *`与`char *`,例如每种类型都有一组单独的参数寄存器。 – 2012-02-20 16:13:23

2

您是对的,sortcmp的签名与qsort的要求不符。你的更正是正确的。 wordcmp也应该被设置为const-正确的,因为在技术上你会丢失一些const-一路上。

int wordncmp(const char *p, const char* q)