You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言:函数名自指时&取址为何仍为函数地址及指针调用疑问

关于函数名、&函数名与函数指针调用的疑问解答

咱们一步一步拆解这两个C语言函数指针的经典“反直觉”问题:

为什么&f和f得到的都是函数地址?

首先得纠正一个误解:函数名本身不是“指向自身的指针”,它本质是一个函数类型的标识符。但在C语言的绝大多数表达式场景中,函数名会被编译器隐式转换为指向该函数的指针——这是C标准规定的自动转换,只有两种例外情况:

  • 函数名作为sizeof的操作数(不过sizeof(函数名)本身是非法的,因为函数没有“大小”这个属性)
  • 函数名作为&运算符的操作数

当你写&f时,&作用于函数类型的标识符,得到的结果就是指向该函数的指针;而直接写f时,编译器会自动把函数类型转换成函数指针。这两种方式得到的指针值完全相同,因为函数的“地址”就是它的代码入口点——函数不是存储在栈/堆上的变量,不存在“函数指针的地址”这种东西,所以&f不会返回“指针的指针”,而是和f等价的函数指针。

你可以用代码验证这个结论:

#include <stdio.h>

void f(int a) {}

int main() {
    void (*p)(int) = f;
    void (*q)(int) = &f;
    
    // 打印两个指针的地址,结果完全一致
    printf("p = %p\n", (void*)p);
    printf("q = %p\n", (void*)q);
    return 0;
}

为什么(*p)(2)和p(2)都合法?

这依然是C语言隐式转换规则在起作用:

  1. 当你写p(2)时,p是函数指针,函数调用运算符()可以直接接受函数指针作为操作数,编译器会直接通过这个指针找到函数入口执行。
  2. 当你写(*p)(2)时,*p会把函数指针解引用,得到一个函数类型的表达式。但紧接着,在()运算符前,这个函数类型的表达式又会被编译器自动转换回函数指针——相当于绕了一圈又回到了p。

甚至你写(**p)(2)、(***p)(2)都是合法的,因为每次解引用后都会被自动转回去。这是C语言为了简化开发者操作的语法设计,不管你是直接用指针还是解引用后使用,编译器都能正确处理。

看个实际运行的例子:

#include <stdio.h>

void f(int a) {
    printf("Called with a = %d\n", a);
}

int main() {
    void (*p)(int) = &f;
    
    p(2);          // 正常调用
    (*p)(2);       // 解引用后调用,和上面效果一致
    (**p)(2);      // 多次解引用,依然正常运行
    return 0;
}

总结一下:这些都是C标准规定的隐式转换特性,目的是让函数指针的使用更灵活,不用写繁琐的冗余语法。

内容的提问来源于stack exchange,提问作者Zahra19977

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:23:23