在C/C++中,对函数名使用&运算符是允许的,但通常没有必要,因为函数名在大多数表达式中会自动退化为函数指针。以下是详细分析:
1. 标准规定(C/C++ 一致)
- C99 标准(§6.3.2.1):
函数指示符(function designator)是具有函数类型的表达式。除非它是 sizeof 或 & 运算符的操作数,否则会将其转换为指向函数的指针。
- C++ 标准(ISO/IEC 14882):
函数名在需要指针的上下文中会自动转换为函数指针(函数到指针的隐式转换)
2. 函数名与&运算符的行为
(1) 函数名自动退化为指针
在C/C++中,函数名在表达式中(除了少数例外,如sizeof或decltype)会隐式转换为指向该函数的指针。例如:
#include <stdio.h>
int func()
{
return 42;
}
/*
函数名在表达式中(除少数例外,如sizeof()或decltype)会隐式转换为指向该函数的指针。
func和&func两种写法生成的机器码相同,因为编译器会忽略多余的&.
*/
int main()
{
int (*func_ptr1)() = func;
int (*func_ptr2)() = &func;
printf("%p, ret=%d\n", (void *)func_ptr1, func_ptr1());
printf("%p, ret=%d\n", (void *)func_ptr2, func_ptr2());
}
0x400596, ret=42
0x400596, ret=42
funcPtr1和funcPtr2会指向相同的地址(即foo的入口地址)。
(2) 直接调用时的等价性
foo(); // 隐式转换为 (&foo)()
(&foo)(); // 显式取地址后调用
- 两种写法生成的机器码完全相同,因为编译器会忽略多余的
&。
|
表达式 |
结果 |
等价性 |
|
|
函数指针 |
与 |
|
|
函数指针 |
与 |
|
|
非法(编译错误) |
- |
|
|
函数指针 |
与 |
3. 特殊情况:&的显式使用
虽然结果相同,但在以下场景中显式使用 & 可能影响语义或可读性:
(1) 类型系统视角
foo的类型是 函数类型(int())。&foo的类型是 函数指针类型(int(*)())。
但在赋值或调用时,编译器会自动调整类型,因此实际行为无差异。
(2) 与sizeof或decltype结合时的区别
sizeof(foo); // 错误:不能对函数名取sizeof
sizeof(&foo); // 合法:返回指针的大小(如8字节)
// c++支持decltype,C语言不支持decltype
decltype(foo) f1; // f1的类型是 int()(函数类型)
decltype(&foo) f2; // f2的类型是 int(*)()(函数指针类型)
- 显式使用
&会改变类型推导的结果。
4, 代码示例验证
#include <stdio.h>
int func()
{
return 42;
}
void demo2()
{
printf("function called\n");
}
/*
函数名在表达式中(除少数例外,如sizeof()或decltype)会隐式转换为指向该函数的指针。
func和&func两种写法生成的机器码相同,因为编译器会忽略多余的&.
*/
int main()
{
int (*func_ptr1)() = func;
int (*func_ptr2)() = &func;
printf("%p, ret=%d\n", (void *)func_ptr1, func_ptr1());
printf("%p, ret=%d\n", (void *)func_ptr2, func_ptr2());
// 验证取地址和直接使用的等价性
void (*ptr1)() = demo2;
void (*ptr2)() = &demo2;
printf("demo=%p\n", (void *)demo2);
printf("&demo=%p\n", (void *)&demo2);
printf("ptr1=%p\n", (void *)ptr1);
printf("ptr2=%p\n", (void *)ptr2);
// 所有调用方式都有效
demo2(); //直接调用
ptr1(); // 指针调用
ptr2(); // 指针调用2
(&demo2)(); // 对地址直接调用->合法
(*&demo2)(); // 对地址解引用调用(组合操作)-->合法
}
输出结果(所有地址值相同):
0x4005d6, ret=42
0x4005d6, ret=42
demo=0x4005e1
&demo=0x4005e1
ptr1=0x4005e1
ptr2=0x4005e1
function called
function called
function called
function called
function called
5,何时需要显式使用 &?
虽然技术上可选,但在以下场景推荐显式取地址:
// 场景1:提高代码清晰度
signal(SIGINT, &handler); // 明确传递函数地址
// 场景2:C++ 重载决议
static_cast<void (*)()>(&func); // 明确指定函数类型
// 场景3:模板元编程
std::invoke(&std::sort, vec.begin(), vec.end()); // 避免歧义
6,总结
- 结果相同:对函数名使用
&在调用或赋值时通常与省略&效果相同。两者都直接返回函数的入口地址,无任何区别。普通代码中可自由选择func或&func. - 类型差异:
func是函数类型,&func是函数指针类型,但编译器会自动调整。 - 显式
&的用途:在需要明确类型或强调语义时推荐使用&func,否则建议省略。

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



