C++函数名与函数指针的转换机制
C++编程中经常遇到函数名(如fun)和函数指针(如p)混用的情况。本文将深入解析两者在底层内存地址上的联系,解释编译器如何隐式执行"Function-to-pointer conversion",并通过代码演示在不同写法下调用函数的等效性。
1. 核心概念:函数名即地址
在C/C++程序中,变量(如int a)占用特定内存空间(例如4字节),其起始地址(如0XFF0A)是该变量的标识。类似地,函数也是存储在代码段中的独立区域,每个函数都有一个唯一的入口地址(Entry Point)来标识自己。
当你定义一个函数时:
int fun(int) { ... }
fun作为一个标识符,本质上映射到该函数的入口地址。虽然fun本身不是指针类型,但在逻辑上它代表了函数的位置。若对变量取地址(&a)返回的是地址值,同理对函数取地址(&fun)也会返回该函数的入口地址。
2. 隐式转换机制
在使用函数进行调用的过程中,存在一个重要的编译规则:Function-to-pointer conversion(函数到指针的转换)。
- 规则一:编译器在处理
fun(2)这类调用时,会隐地将函数名fun转换为指向该函数的指针。 - 规则二:如果你显式写出
(&fun)(2),因为&fun本身就是获取的地址,所以同样能正确工作。 - 规则三:对于多次解引用的写法,如
(*******fun)(2),编译器会在看到fun时先转为指针,然后对其进行解引用操作,最后再进行一次隐式转换恢复为可调用状态。这种反复转换是编译器内部完成的,开发者无需刻意修饰。
3. 实例验证
第1步:观察输出结果
目的:验证函数名、带星号函数名及取地址函数名在内存层面的指向是否一致。
#include<iostream>
using namespace std;
void fun(int a)
{
}
int main()
{
cout<<fun<<endl;
cout<<*fun<<endl;
cout<<&fun<<endl;
cout<<*****fun<<endl;
}运行该程序后输出的值完全相同,它们均指向同一个函数入口地址的指针值。这证明了在表达式上下文中,fun、*fun和&fun具有等价的语义。
第2步:定义并使用函数指针变量
目的:学习如何将函数赋值给自定义的函数指针并正常调用。
假设我们需要定义一个函数指针类型来接收上述函数:
#include<iostream>
using namespace std;
int fun(int a)
{
cout<<"fun"<<endl;
return 0;
}
void main()
{
// 定义三种不同的赋值方式
int(*p)(int)=fun; // 直接赋值函数名
int(*p1)(int)=*fun; // 对函数名解引用后赋值
int(*p2)(int)=&fun; // 对函数名取地址后赋值
// 调用测试
p(1);
p1(1);
p2(1);
}这三个函数指针p、p1、p2都能正常触发fun函数。理解的关键在于:无论赋值来源如何写法,最终存入指针变量中的都是同一内存地址。
第3步:指针变量的间接调用
目的:掌握使用已赋值的指针变量进行函数调用的不同表现形式。
#include<iostream>
using namespace std;
int fun(int a)
{
cout<<"fun"<<endl;
return 0;
}
void main()
{
int(*p)(int)=fun;
p(1); // 常规调用
// (&p)(1); // 错误!p是指针变量,&p是其本身的地址,非法
(*p)(1); // 解引用指针后调用
(****p)(1); // 多层解引用后再调用
}注意以下细节:
- 关于
(&p)(1)报错:p是一个存放地址的变量,对它取地址得到的是变量p自身的内存地址,而非函数的入口地址,因此无法用于调用。 - 关于临时值限制:连续对
fun多次取地址(如&&fun)通常是非法的,因为在获取函数指针这一临时值的瞬间,并没有实际的物理内存块专门用来存放这个中间态,故不能对临时指针再次求地址。
总结
理解C++函数名的关键在于将其视为一种特殊的地址标识符。编译器会自动处理从函数名到函数指针之间的各种转换,包括取地址&和解引用*。在编写代码时,无论是直接使用函数名还是通过预先定义的函数指针调用,其背后的底层逻辑是一致的。以上就是C++函数名与函数指针关联性的详细内容,更多关于C++内存模型与指针用法的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













