让我们看看下面的代码:
int main ()
{
int a = 5;
int&b = a;
cout << a << endl; // 5 is displayed
cout << b << endl; // 5 is also displayed
return 0;
}这就是我在调试器中看到的行为。
int a = 5将在内存地址-0x14(%rbp)中指定值5。
int& b = a将在内存地址-0x8(%rbp)中指定值-0x14(%rbp)。
当我执行cout << a << endl时,将显示a(即-0x14(%rbp))地址中的值。
但是,当我执行cout << b << endl时,b(即-0x8(%rbp))地址中的值被确定为一个地址,然后显示该地址(-0x14(%rbp))的值。
这是std::cout调用的程序集:
20 cout << a << endl;
0000000000401506: mov -0xc(%rbp),%eax
0000000000401509: mov %eax,%edx
000000000040150b: lea 0x6f8c9c6e(%rip),%rcx # 0x6fccb180 <libstdc++-6!_ZSt4cout>
0000000000401512: callq 0x4015f8 <_ZNSolsEi>
0000000000401517: lea 0xe2(%rip),%rdx # 0x401600 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_>
000000000040151e: mov %rax,%rcx
0000000000401521: callq 0x401608 <_ZNSolsEPFRSoS_E>
21 cout << b << endl;
0000000000401526: mov -0x8(%rbp),%rax
000000000040152a: mov (%rax),%eax
000000000040152c: mov %eax,%edx
000000000040152e: lea 0x6f8c9c4b(%rip),%rcx # 0x6fccb180 <libstdc++-6!_ZSt4cout>
0000000000401535: callq 0x4015f8 <_ZNSolsEi>
000000000040153a: lea 0xbf(%rip),%rdx # 0x401600 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_>
0000000000401541: mov %rax,%rcx
0000000000401544: callq 0x401608 <_ZNSolsEPFRSoS_E>
24 return 0;问题:
cout指令非常相似,a是如何与b区别对待的?
发布于 2015-01-10 17:14:25
简而言之,事实并非如此。
CPU本身并不关心哪种类型存储在哪里,它只是执行编译器生成的指令。
编译器知道b是一个引用,而不是一个int。因此,它指示CPU将b视为指针。
如果您查看程序的汇编代码,您会发现访问a和b的指令是不同的:b的部分包含额外的指令
mov (%rax),%eax这是取消引用的步骤。(在这个程序集表示法中,括号表示取消引用,所以这个指令意味着eax =*rax之类的东西)。
发布于 2015-01-10 17:16:52
我想你绝对没有要求优化。尽管如此,我还是希望访问a和访问b可以生成完全相同的代码(至少在本例中是这样)。
关于编译器如何知道:a和b有不同的类型,所以编译器知道如何对它们执行不同的操作。该标准的设计使得将int&替换为int* const,然后在每次访问(初始化除外)上自动取消引用将导致一致的实现;看起来这就是编译器正在做的事情。
https://stackoverflow.com/questions/27878830
复制相似问题