《Programming Pearls》中的 qsort 函数出错?
是我一个人还是Programming Pearls 中的代码是错误的(quicksort需要2个const void,不是吗?)如果是这样,我的解决方案对吗? 抱歉,刚刚学习...
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);
}
is it just me or this code in Programming Pearls is wrong (quicksort wants 2 const voids, no?) If so, is my solution right? Apologies, just learning...
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);
Is this a solution?
int sortcmp(const void *p, const void *q)
{ return wordncmp(* (char * const *) p, * (char * const *) q);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
第一个代码示例可能适用于几乎任何编译器和 CPU; 然而,如果您严格遵守 C 标准,那么从技术上讲,这是未定义的行为。
正如您所说,
qsort()
的最后一个参数是一个指向带有两个const void*
类型参数的函数的指针。sortcmp
采用不同的参数。 您的编译器应该向您发出有关不兼容类型签名或其他内容的警告。 在任何情况下,都会执行从一种类型的函数到另一种类型的函数的转换。C 标准指定您可以将函数指针强制转换为其他不同类型的函数指针,但不能取消引用和调用强制转换的函数指针。 但是,如果您将函数指针重新转换回其原始类型,则调用它已定义的行为 - 它会调用原始函数。
由于您要从
int (*)(char**, char**)
转换为int (*)(const void*, const void*)
,然后最终 qsort() 调用比较器函数而不将其转换回 int (*)(char**, char**) ,这是未定义的行为。然而,由于实际上在所有体系结构上,
char **
和const void*
都以相同的方式表示,因此函数调用几乎总是有效。如果您想获得定义的行为,则必须确保比较器函数具有正确的类型签名,然后可以将参数转换为正确的类型。 您的解决方案完全正确,并且不违反那里的 C 标准。 在
const
正确性方面做得很好——很多人不明白char * const *
的确切含义。您还应该让
wordncmp()
接受const char*
的参数,因为您没有修改这些参数。附注:从技术上讲,您也无法将函数指针转换为数据指针(例如
void*
),反之亦然。 该标准允许函数指针和数据指针具有不同的大小。 即使它可以在您的计算机上运行,也不能保证始终有效。The first code sample will probably work with virtually any compiler and CPU; however, it is technically undefined behavior, if you follow the C standard to the letter.
As you said, the last argument to
qsort()
is a pointer to a function taking two arguments of typeconst void*
.sortcmp
takes different arguments. Your compiler should give you a warning about incompatible type signatures or something. In any case, a cast is being performed from a function of one type to a function of another type.The C standard specifies that you can cast function pointers to other function pointers with different types, but you cannot dereference and invoke the casted function pointer. However, if you re-cast the function pointer back to its original type, then calling that has defined behavior -- it calls the original function.
Since you're casting from a
int (*)(char**, char**)
to aint (*)(const void*, const void*)
, and then eventuallyqsort()
is invoking your comparator function without casting it back toint (*)(char**, char**)
, that's undefined behavior.However, since virtually on all architectures, a
char **
and aconst void*
are represented the same way, the function call will pretty much always work.If you want to get defined behavior, you have to make sure your comparator function has the proper type signature, and then you can cast the arguments to the proper type. Your solution is exactly correct and does not violate the C standard there. Well done on
const
-correctness -- a lot of people don't understand exactly whatchar * const *
means.You should also make
wordncmp()
take parameters ofconst char*
, since you're not modifying the parameters.Side note: You also technically can't cast a function pointer to a data pointer (e.g. a
void*
) or vice-versa. The standard allows for function pointers and data pointers to have different sizes. Even if it works on your computer, it's not guaranteed to always work.您是对的,
sortcmp
的签名与qsort
期望的不匹配。 你的修正是正确的。wordcmp
也应该是const
正确的,因为从技术上讲,您在此过程中失去了一些const
特性。You are correct, the signature for
sortcmp
does not match whatqsort
expects. Your correction is right.wordcmp
should also be madeconst
-correct as you are technically losing some of theconst
-ness along the way.