最近,我一直在研究K& R的C编程语言。
在5.11节中,它们涵盖了函数的指针,并在输入他们的示例之后 - 一个快速实现,我们提供了一个指向我们想要使用的比较函数的指针 - 我从编译器收到警告:指针类型不匹配在条件表达式中。 (我的编译器是OS X 10.5.6上的gcc 4.0.1)
触发警告的示例中的行是:
qsort((void **) lineptr, 0, nlines-1,
(int (*)(void*, void*))(numeric ? numcmp : strcmp));
该程序在没有segfaulting的情况下执行,但我喜欢尽可能地发出警告,或者至少了解它们的原因。
numcmp的函数声明如下:
int numcmp(char *, char *);
但根据联机帮助页,stcmp有这个签名:
int strcmp(const char *s1, const char *s2);
由于方法签名略有不同,警告是否简单?忽视警告有什么后果?
答案 0 :(得分:7)
虽然您可以隐式地将char *强制转换为void *,但对于具有这些类型的函数指针(没有警告),您不能这样做。编译器对函数签名的类型匹配更加小心。
更不用说在qsort中发生的事情恰恰相反:也就是说,void *将被转换为numcmp中的char *和strcmp中的const char *。
编译器应该在这些情况下发出警告。如果你真的必须使用一个与参数类型不同的函数,也许你应该使用一个匹配类型的包装函数,然后在调用原始函数时进行适当的显式转换。
例如:
static int strcmp_wrapper(void* s1, void* s2) {
return strcmp((char*)s1, (char*)s2);
}
static int numcmp_wrapper(void* n1, void* n2) {
return numcmp((char*)n1, (char*)n2);
}
qsort((void **) lineptr, 0, nlines-1,
(numeric ? numcmp_wrapper : strcmp_wrapper));
qsort的现代签名是
void
qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *, const void *));
const
的问题似乎没有在您的问题中发挥作用,但K& R没有const
。
答案 1 :(得分:3)
简短回答:K& R不知道C.
答案很长:当他们开始时,没有人知道C,所以他们有点不知所措。所以他们在进行的时候会有所补偿。
(略微)长篇答案的轻浮形式:自K& R编写以来,语言已经发展(有些人会说已经改变),但除非你有电子书版本使用动态示例变形,您的K& R副本中的示例将无法跟上“新的和已批准的”(“现在使用更多ANSI!”)语言。
答案 2 :(得分:1)
尝试和诊断它的一种方法是看看如果用?:只用两个中的一个替换表达式会发生什么。
如果它只发生在strcmp而不是numcmp,那么很可能是因为const char *。我认为虽然char *总是可以转换为void *,但你不能将const char *转换为void *为“safe”。
如果两者兼而有之,那么可能这是关于函数指针的一些问题,其中char *转换为void *有效,但签名应该相同并且有空格而不是字符是一个问题。