指令集如何区分价值与参考

时间:2015-01-10 17:08:24

标签: c++ memory assembly

我们来看看这段代码:

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;

问题:

两个std :: cout说明非常相似,ab的处理方式有何不同?

2 个答案:

答案 0 :(得分:3)

简而言之:它没有。

CPU本身并不关心哪种类型存储在哪里,它只是执行编译器生成的指令。

编译器知道b是引用,而不是int。因此它指示CPU将b视为指针。

如果您查看程序的汇编代码,您会看到访问ab的说明不同:b的部分包含额外的指令< / p>

mov (%rax),%eax

这是解除引用步骤。 (在这个汇编表示法中,括号表示解除引用,因此该指令的含义类似于eax = * rax)。

答案 1 :(得分:2)

我认为你已经要求绝对没有优化。虽然连 那么,我本来希望访问a并访问b来生成 完全相同的代码(在这种情况下,至少)。

关于编译器如何知道:ab有不同之处 类型,因此编译器知道用它们做不同的事情。该 标准已设计为将int&替换为int* const, 然后在每次访问时自动解除引用(除了 初始化)将导致符合要求的实现;它看起来 这就是你的编译器正在做的事情。