K&R 5.11 函数指针 C 中的混淆线
Confusing line in K&R 5.11 function pointers C
main()
这一行的最后一个参数让我迷路了
// declaration
void qsort(char *linep[], int left, int right, int (*compare)(void *, void*);
// use
main(){
qsort((void**) lineptr, 0, nlines-1, (int (*)(void*,void*))(numeric ?
numcmp : strcmp));
}
我理解三元运算符,但让我们说数字 == 0 那么这是什么意思?
(int (*)(void *, void*))strcmp;
函数参数的数据类型是否不匹配?
int strcmp(const char*, const char*);
void qsort( , , , int(*)(void*)(void*);
我可以类型转换函数指针吗?
在您的代码中,使用强制转换
(int (*)(void *, void*))strcmp;
表示,strcmp()
是一个函数指针,有两个void *
参数和returns一个int
.
通常,对于函数指针,转换是一个非常糟糕的主意,正如引用自 C11
,第 6.3.2.3 章
[...] If a converted
pointer is used to call a function whose type is not compatible with the referenced type,
the behavior is undefined.
但是,在您的情况下,对于参数类型,char *
和 void *
互为别名,因此类型转换类型 compatible 与实际有效类型,因此(稍后)定义了函数调用。
是的,您可以将函数指针转换为指向具有不同签名的函数的指针。根据您的调用约定(谁清理堆栈?调用者还是被调用者?)如果参数数量不同或参数大小不同,调用该函数将是错误的。
这里也不是这种情况:在您的标准架构(sun 工作站、Linux PC、raspberry PI)上,指向不同数据类型的参数指针以相同的方式表示,因此不会造成任何损害。该函数将从堆栈中读取 4 或 8 字节的值,并将指向的内存解释为预期类型的数据(它应该有,例如,不要在字符串上使用浮点比较函数;它可能会抛出,因为任意位模式可以是 NaN 等)。
我想提醒您,今天的标准库 qsort
与 K&R 的示例具有不同的函数签名(和语义)。今天的qsort
得到一个指向元素向量开头的指针,用指向数组中元素的指针调用比较函数;在字符串指针数组的情况下,参数是 指向指针 的指针,不适合 strcmp()
。参数必须首先取消引用。 linux man page for qsort 有一个 strcmp
包装器的例子,它就是这样做的。 (手册页 Web 导出看起来有些乱码,但仍然可读。)
main()
这一行的最后一个参数让我迷路了
// declaration
void qsort(char *linep[], int left, int right, int (*compare)(void *, void*);
// use
main(){
qsort((void**) lineptr, 0, nlines-1, (int (*)(void*,void*))(numeric ?
numcmp : strcmp));
}
我理解三元运算符,但让我们说数字 == 0 那么这是什么意思?
(int (*)(void *, void*))strcmp;
函数参数的数据类型是否不匹配?
int strcmp(const char*, const char*);
void qsort( , , , int(*)(void*)(void*);
我可以类型转换函数指针吗?
在您的代码中,使用强制转换
(int (*)(void *, void*))strcmp;
表示,strcmp()
是一个函数指针,有两个void *
参数和returns一个int
.
通常,对于函数指针,转换是一个非常糟糕的主意,正如引用自 C11
,第 6.3.2.3 章
[...] If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
但是,在您的情况下,对于参数类型,char *
和 void *
互为别名,因此类型转换类型 compatible 与实际有效类型,因此(稍后)定义了函数调用。
是的,您可以将函数指针转换为指向具有不同签名的函数的指针。根据您的调用约定(谁清理堆栈?调用者还是被调用者?)如果参数数量不同或参数大小不同,调用该函数将是错误的。
这里也不是这种情况:在您的标准架构(sun 工作站、Linux PC、raspberry PI)上,指向不同数据类型的参数指针以相同的方式表示,因此不会造成任何损害。该函数将从堆栈中读取 4 或 8 字节的值,并将指向的内存解释为预期类型的数据(它应该有,例如,不要在字符串上使用浮点比较函数;它可能会抛出,因为任意位模式可以是 NaN 等)。
我想提醒您,今天的标准库 qsort
与 K&R 的示例具有不同的函数签名(和语义)。今天的qsort
得到一个指向元素向量开头的指针,用指向数组中元素的指针调用比较函数;在字符串指针数组的情况下,参数是 指向指针 的指针,不适合 strcmp()
。参数必须首先取消引用。 linux man page for qsort 有一个 strcmp
包装器的例子,它就是这样做的。 (手册页 Web 导出看起来有些乱码,但仍然可读。)