问题编译K&R示例
我在编写本书第5.11节中介绍的示例程序时遇到了问题。 我删除了大部分代码,只留下了相关内容。
#define MAXLINES 5000 char *lineptr[MAXLINES]; void qsort1(void *lineptr[], int left, int right, int (*comp)(void *, void *)); int numcmp(char *, char *); main(int argc, char *argv[]) { int numeric = 1; /* ... */ qsort1((void**) lineptr, 0, 100, (int (*)(void*, void*))(numeric ? numcmp : strcmp)); } void qsort1(void *v[], int left, int right, int (*comp)(void *, void *)) { /* ... */ } int numcmp(char *s1, char *s2) { /* ... */ }
问题是代码无法编译(我正在使用Digital Mars编译器)。 我得到的错误是这样的:
qsort1((void**) lineptr, 0, nlines - 1, (int (*)(void*, void*))(numeric ? numcmp : strcmp)); ^ go.c(19) : Error: need explicit cast to convert from: int (*C func)(char const *,char const *) to : int (*C func)(char *,char *) --- errorlevel 1
虽然我正确地粘贴了书中的代码,但声明必定有问题。 我不知道做出正确的更改(关于函数指针的部分当然可以更广泛地编写)。
编辑:我应该提到我正在阅读本书的ANSI版本。
我认为错误来自于旧C不知道const的事实:strcmp有两个指向非const字符( char *
)我认为(这可能是它编译的原因,但不是你的编译器)。 但是,现在strcmp采用char const*
( const char*
是一回事)。 将您的函数原型更改为:
int numcmp(char const*, char const*);
这是一个常见的问题:)
以下行告诉qsort
期望指向具有两个void *参数的函数的指针。 不幸的是, strcmp
需要两个不可修改的字符串,因此它的签名是
int (*comp)(const char*, const char*)
而不是你拥有的:
int (*comp)(void *, void *)
更改qsort1
和numeric
的签名:
qsort1(void *v[], int left, int right, int (*comp)(const void *, const void *))
和:
int numcmp(const char*, const char*)
qsort()
或bsearch()
期望的标准函数指针具有原型:
int comparator(const void *v1, const void *v2);
代码中定义的qsort1()
需要:
int comparator(void *v1, void *v2);
代码中定义的比较器函数没有该原型,并且不同的函数指针类型之间没有自动转换。
因此, qsort1()
修复程序是:
- 引入一个强制转换:
(int (*)(void *, void *))
,或 -
重写比较器:
int numcmp(void *v1, void *v2) { char *s1 = v1; char *s2 = v2; ... } int str_cmp(void *v1, void *v2) // Note new function name! { return(strcmp(v1, v2)); }
显然,对qsort1()
的调用将引用str_cmp
而不是strcmp
。 作者试图避免使用中间函数,但与现在使用的(合法的)繁琐的编译器相违背。
标准版本的qsort()
需要一堆const
限定符,如本答案的第一个版本所示。
请注意, strcmp
需要两个const参数,而numcmp
则不需要。 因此,这两个函数的类型不匹配,而且? :
? :
运营商会抱怨。
做其中一个:
- 根据
numcmp
更改numcmp
以匹配strcmp
原型 -
推送
(int (*)(void*, void*))
里面的? :
? :
,例如numeric ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp
自从我完成任何纯C编程以来已经有一段时间了,我不确定新标准。
但是,转换为void **会创建一个指向指针的指针,其中函数需要指向数组的指针。 当然,它们在内部是相同的,但强大的类型检查会将其视为错误。
重写qsort接受**而不是* [],你应该没问题。