6

可能重复:
编译 K&R 示例时出现问题

最近我一直在研究 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));

该程序在没有段错误的情况下执行,但我喜欢尽可能消除所有警告,或者至少了解它们的原因。

numcmp 的函数声明如下所示:

 int numcmp(char *, char *);

但是根据手册页, stcmp 有这个签名:

 int strcmp(const char *s1, const char *s2);

由于方法签名略有不同,警告是否简单?忽视警告的后果是什么?

4

3 回答 3

6

Although you can implicitly cast a char* to a void*, you can't do the same for a function pointer with those types (without a warning). The compiler is more careful with type matching on function signatures.

Not to mention that what's happening inside qsort would be the opposite: that is, a void* would be cast to a char* in numcmp and const char* in strcmp.

And the compiler should issue a warning in these cases. If you really have to use a function that doesn't have the same types as parameters, perhaps you should use a wrapper function that does match the types, and then does the appropriate explicit cast when calling the original function.

For instance:

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));

And the modern signature for qsort is

void
qsort(void *base, size_t nel, size_t width,
      int (*compar)(const void *, const void *));

The issue of const doesn't seem to come into play in your question, but K&R did not have const.

于 2009-03-20T04:57:19.937 回答
4

简短回答:K&R 不知道 C。

冗长的回答:当他们开始的时候,没有人知道 C,这使他们受到了阻碍,所以他们在进行过程中有点编造。

(稍微)不那么轻率的长答案形式:自从编写 K&R 以来,该语言已经发展了很多(有些人会说发生了变化),但是除非您获得具有动态示例变形的电子书版本,否则您副本中的示例K&R 不会跟上“新的和认可的”(“现在有了更多的 ANSI!”)语言。

于 2009-03-20T04:52:50.897 回答
1

尝试诊断它的一种方法是查看如果将表达式替换为 ?: 仅使用两者之一会发生什么。

如果它只发生在 strcmp 而不是 numcmp,那么很可能是因为 const char*。我认为虽然 char* 始终可以转换为 void*,但您不能将 const char* 转换为 void* 作为“安全”。

如果两者都有,那么这可能与函数指针有关,其中将 char* 转换为 void* 可以工作,但签名应该相同,并且使用 void 而不是 char 是一个问题。

于 2009-03-20T04:51:30.230 回答