让我们看一下这段代码:
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
将赋值 5
在内存地址-0x14(%rbp)
int& b = a
将赋值 -0x14(%rbp)
在内存地址-0x8(%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;
问题:
两个 std::cout 指令非常相似,a
是怎样的?不同于b
?
最佳答案
简而言之:它没有。
CPU 本身并不关心哪种类型存储在哪里,它只是执行编译器生成的指令。
编译器知道 b
是一个引用,而不是一个 int
。因此它指示 CPU 将 b
视为指针。
如果您查看程序的汇编代码,您会发现访问 a
和 b
的指令是不同的:b 的部分
包含一个额外的指令
mov (%rax),%eax
这是取消引用的步骤。 (在这个汇编符号中,圆括号表示取消引用,所以这条指令的意思类似于 eax = *rax)。
关于c++ - 指令集如何区分值和引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27878830/