为何部分C语言函数仅能通过&运算符获取地址?
函数指针赋值异常问题分析与解决
你在练习《C程序设计语言》(第二版)的函数指针示例时,遇到了一个奇怪的问题:将reva和revn函数直接赋值给函数指针fp时(fp = reva、fp = revn),指针会变成空值,导致段错误;但给这些函数名加上&运算符后(fp = &reva),赋值就正常了。而strcmp、numcmp等函数无论加不加&都能正常赋值。
核心原因:函数类型与指针类型不兼容
你的代码里存在明显的类型不匹配问题:
- 函数指针
fp的类型是int (*)(void*, void*),指向的是接收两个void*参数、返回int的函数。 - 但
reva和revn的声明是int reva(char *, char *)、int revn(char *, char *),参数类型为char*,和fp的参数类型完全不匹配。
在C语言中的规则:
- 直接使用函数名赋值时,会触发函数到函数指针的隐式转换,但如果源函数类型和目标指针类型不兼容,这种转换属于未定义行为——不同编译环境会有不同表现,你遇到的就是赋值后指针为空的情况。
- 加
&显式取函数地址时,相当于直接把内存地址赋值给指针,部分编译器会跳过严格的类型检查,让地址赋值成功,但这本质上还是不符合C标准的写法,只是临时绕过了问题。
正确解决方案:统一函数与指针类型
让函数类型和指针类型完全匹配,才是符合标准的正确做法:
- 修改函数声明,将
reva、revn、numcmp的参数改为void*:
int numcmp(void *, void *); int reva(void *, void *); int revn(void *, void *);
- 修改函数定义,在内部将
void*强制转换为char*:
int numcmp(void *s1, void *s2) { double v1 = atof((char*)s1); double v2 = atof((char*)s2); if(v1 < v2) return -1; else if(v1 > v2) return 1; else return 0; } int reva(void *s1, void *s2) { return -strcmp((char*)s1, (char*)s2); } int revn(void *s1, void *s2) { return -numcmp(s1, s2); }
修改后,所有函数的类型都和fp的类型一致,无论加不加&,赋值都会正常工作,也彻底避免了未定义行为。
内容的提问来源于stack exchange,提问作者user3143158
相关产品推荐
相关产品推荐

