对函数名使用&运算符,结果与不使用&相同么

在C/C++中,对函数名使用&运算符是允许的,但通常没有必要,因为函数名在大多数表达式中会自动退化为函数指针。以下是详细分析:

1. 标准规定(C/C++ 一致)

  • C99 标准(§6.3.2.1):

函数指示符(function designator)是具有函数类型的表达式。除非它是 sizeof & 运算符的操作数,否则会将其转换为指向函数的指针。

  • C++ 标准(ISO/IEC 14882):

函数名在需要指针的上下文中会自动转换为函数指针(函数到指针的隐式转换)

2. 函数名与&运算符的行为

(1) 函数名自动退化为指针

在C/C++中,函数名在表达式中(除了少数例外,如sizeofdecltype)会隐式转换为指向该函数的指针。例如:

#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
  • funcPtr1funcPtr2 会指向相同的地址(即 foo 的入口地址)。
(2) 直接调用时的等价性
foo();       // 隐式转换为 (&foo)()
(&foo)();    // 显式取地址后调用
  • 两种写法生成的机器码完全相同,因为编译器会忽略多余的 &

表达式

结果

等价性

func

函数指针

&func 相同

&func

函数指针

func 相同

*func

非法(编译错误)

-

*&func

函数指针

func 相同

3. 特殊情况:&的显式使用

虽然结果相同,但在以下场景中显式使用 & 可能影响语义或可读性:

(1) 类型系统视角
  • foo 的类型是 函数类型(int())。
  • &foo 的类型是 函数指针类型(int(*)())。
    但在赋值或调用时,编译器会自动调整类型,因此实际行为无差异。
(2) 与sizeofdecltype结合时的区别
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,否则建议省略。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值