我写了一个小程序:
#include <iostream>
using namespace std;
int raw(int &x) {
cout<<x<<endl;
cout<<&x<<endl;
}
int main () {
int s= 1;
int &z=s;
raw(s);
raw(z);
return 0;
}
输出(正如预期的那样):
1
0x7fff5ed36894
1
0x7fff5ed36894
它的工作方式与我预期的一样,但我很好奇这是如何在内部实现的。是函数重载还是别的什么,或者其中一个函数是另一个函数的包装器,以提供用户友好性或编译器自己进行转换?
答案 0 :(得分:7)
这是它在汇编程序中的外观:
int s= 1;
002044A8 mov dword ptr [s],1
int &z=s;
002044AF lea eax,[s]
002044B2 mov dword ptr [z],eax
raw(s);
002044B5 lea eax,[s]
002044B8 push eax
002044B9 call raw (020110Eh)
002044BE add esp,4
raw(z);
002044C1 mov eax,dword ptr [z]
002044C4 push eax
002044C5 call raw (020110Eh)
LEA(在lea eax,[s]
中)表示加载有效地址,以便您了解z
如何有效地包含指向s
位置的指针。
在函数调用之前推送准备参数的指令清楚地表明在两种情况下都得到(相同)指针作为输入。
这是非优化代码。
答案 1 :(得分:5)
当编译器为你的程序生成代码时,当它看到&
说这是一个引用时,它确实产生了一个指针变量[或类似指针的机器代码中的东西]。
因此,z
将保留s
的地址。
当你调用raw(s)
时,编译器会说“啊,所以raw参数是一个引用,意思是s
的地址”。当您执行raw(z)
时,编译器会说“啊,我们已经有了一个引用,所以我们只需要传递z
”的内容,因为您之前将它设置为s
,所以与s
相同的地址。
这完全是应该的。
答案 2 :(得分:3)
内部
int s= 1;
int &z=s;
raw(s);
raw(z);
针对此进行了优化:
int s = 1;
raw(s);
raw(s);
因为在int &z = s;
之后z
变量{{1}}将别名为s到其生命周期的结束。所以基本上它和s一样。