在C/C++中,当使用函数指针调用函数时,解引用操作符*是可选的。以下详细解释原因:
1. 函数指针的自动转换
- 函数指针在调用上下文中会自动转换为函数地址。
例如:
void func(int); // 函数声明
void (*pfunc)(int) = func; // pfunc指向func
-
pfunc(42);// 直接调用(不加*)(*pfunc)(42);// 解引用后调用(加*)
- 两者完全等价,编译器会生成相同的机器码。
2. 语言标准规定
- C/C++标准明确允许这种灵活性:
-
- C99标准(§6.5.2.2):函数调用操作符
()要求一个指向函数的指针作为其操作数。 - C++标准(ISO/IEC 14882):函数名或函数指针在调用时自动转换为函数地址。
- C99标准(§6.5.2.2):函数调用操作符
- 因此,无论是否显式解引用,只要表达式最终是函数地址,调用就能正确执行。
3. 解引用的本质
- 解引用函数指针(如
*pfunc)得到的仍是函数地址本身,而非函数内容。 - 这是因为函数在内存中没有“值”的概念,只有入口地址。因此:
-
pfunc→ 函数地址*pfunc→ 仍是相同的函数地址(与**pfunc、***pfunc等相同)
- 编译器会忽略多余的
*,仅关注最终地址。
4. 代码一致性示例
#include <stdio.h>
void hello()
{
printf("hello\n");
}
/*
函数指针在调用上下文中会自动转换为函数地址。
解引用函数指针(*fp)得到的仍是函数地址本身,而非函数内容。这是一位函数在内存中没有“值”的概念,只有入口地址。
所以fp是函数地址,*fp也是函数地址。编译器在处理函数指针时,会忽略多余的*,仅关注最终地址。
因此,在使用函数指针调用时,加*和不加*均可,因为编译器会忽略解引用操作,直接使用函数地址。推荐使用fp(),更简洁,更接近普通函数用法
*/
int main()
{
void (*fp)() = hello;
hello();
fp(); // 指针调用函数,不加*
(*fp)(); // 解引用调用函数,加*
(**fp)(); // 多次解引用调用函数,仍有效
}
输出均为:
hello
hello
hello
hello
5. 设计初衷
- 提高代码可读性:直接使用指针名调用更简洁。
- 兼容函数行为:使函数指针的用法接近普通函数名。
- 历史原因:早期C语言要求显式解引用(如
(*ptr)()),后为简化语法放宽限制。
总结
函数指针调用时加*或不加*均可,因为编译器会忽略解引用操作,直接使用函数地址。这是语言设计的人性化体现:
- 推荐风格:直接
ptr()更简洁。 - 显式解引用:
(*ptr)()可强调是指针调用,增强可读性。
两者无性能差异,按团队规范选择即可。
299

被折叠的 条评论
为什么被折叠?



