C++中按引用传递函数:如何获取其内存地址?
C++函数引用与指针的地址获取疑问
我是C++新手,出于兴趣学习,目前仍在理解引用和解引用语法。我理解&foo会返回对象foo的引用,且通过&foo应该能像指针一样获取引用指向对象的内存地址,如下例能正常获取foo的地址:
//EXAMPLE 1 - 符合预期 void useFooRef(int &foo) { cout << "using foo @ " << &foo << endl; //输出:using foo @ 0x16eebb4e8 //无警告! } int foo = 1; int main() { useFooRef(foo); return (0); }
但当foo是函数时,用指针接收能正常获取地址,而我了解到按引用传递更安全可避免空指针,但用引用接收时会出现编译器警告,输出结果异常:
//EXAMPLE 2 void useFooPtr(int (*foo)()) { cout << "using foo @ " << &foo << endl; //输出:using foo @ 0x16fb634c8 //无警告! }; void useFooRef(int (&foo)()) { cout << "using foo @ " << &foo << endl; //输出:using foo @ 1 //警告:reference cannot be bound to dereferenced null pointer in well-defined C++ code }; int foo() { return (3); }; int main() { useFooPtr(foo); useFooRef(foo); return (0); }
我目前对C++的认知是:变量名包含自身内存槽的元数据,引用存储指向对象的内存槽地址,指针有自身内存槽,存储指向对象的内存槽地址。我想请教:传递函数时,引用和指针接收的元数据有何不同?为何普通int引用能通过&foo获取地址,函数引用却不行,而函数指针在两种场景下都能正常获取地址?
核心差异:函数与普通变量的本质区别
首先要明确:函数不是对象,而int这类普通变量是对象。C++里的引用分为「对象引用」和「函数引用」,两者的行为因为目标的本质不同而有差异。
1. 普通int引用的&foo行为
对于int &foo这种对象引用:
- 引用本身是变量的别名,没有独立的内存槽(标准未要求为引用分配内存,编译器通常会优化掉)。
- 当你写
&foo时,实际上是取被引用对象的地址,也就是原int foo的内存地址,这和直接取原变量地址完全等价,所以输出正常,无警告。
2. 函数指针与函数引用的&foo行为
先理清函数名的隐式转换:
- 函数名
foo在大多数语境下会隐式转换成指向自身的函数指针(比如传给useFooPtr时,foo自动变成&foo)。 - 但
&foo对于函数来说,直接返回的就是函数指针(函数本身没有内存槽,函数的"地址"就是其机器码在内存中的起始位置)。
函数指针的情况
int (*foo)()是一个函数指针变量,它有自己的内存槽,存储的是函数的地址。
- 当你写
&foo时,取的是这个指针变量自身的内存地址,也就是栈上存储函数指针的那个位置的地址,所以输出是一个正常的栈地址,无警告。
函数引用的情况
int (&foo)()是函数的别名,和对象引用一样,它没有独立的内存槽。
- 当你写
&foo时,按照C++标准,函数引用的&操作会直接返回函数的指针(因为函数本身没有地址可被取,引用只是别名)。但这里出现了问题:cout无法直接输出函数指针,会把它当作bool类型处理,非空函数指针会被转换成true,也就是输出1,这就是你看到的异常结果。 - 至于编译器警告,这是部分编译器的过度提示,因为你绑定的是合法的函数,并非空指针,这个警告可以忽略。
3. 关于"元数据"的认知修正
你的认知有一点偏差:
- 引用没有独立的内存槽(标准未规定,编译器可能会在某些场景下为引用分配内存,但这是实现细节,不是标准行为),它只是被引用对象的别名。
- 函数本身不是对象,没有"内存槽",函数的地址是其机器码在程序内存中的起始位置,不是某个变量的存储地址。
内容的提问来源于stack exchange,提问作者joshstrike
相关产品推荐
相关产品推荐

