【问题标题】:How do instruction sets differentiate value from reference指令集如何区分价值和参考
【发布时间】:2015-01-10 17:08:24
【问题描述】:

让我们看看这段代码:

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&amp; b = a 将在内存地址-0x8(%rbp) 中赋值-0x14(%rbp)

当我执行cout &lt;&lt; a &lt;&lt; endl 时,将显示 a 地址中的值(即 -0x14(%rbp))。

但不知何故,当我执行cout &lt;&lt; b &lt;&lt; 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 的处理方式有何不同?

【问题讨论】:

  • 这不是 CPU 所做或理解的事情。这是语言的规则。您的编译器告诉 CPU 取消引用该引用。

标签: c++ memory assembly


【解决方案1】:

简而言之:它没有。

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

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

如果您查看程序的汇编代码,您会发现访问ab 的指令是不同的:b 的部分包含一个额外的指令

mov (%rax),%eax

这是取消引用的步骤。 (在此汇编符号中,括号表示取消引用,因此该指令表示类似 eax = *rax)。

【讨论】:

  • 为了更清楚我的问题没有注明日期,我看不出用于获取 a 的值和 b 所指的值的指令集有什么不同
  • 我愿意。对于cout &lt;&lt; b,有000000000040152a: mov (%rax),%eax 用于cout &lt;&lt; b,这正是取消引用指针。 cout &lt;&lt; a没有这样的说明)
  • 啊等等,为什么这条指令取消引用?是括号吗?!?
  • 没错。 (%rax) 表示“存储在rax 中的地址的内存”。
  • 啊我不知道这个..谢谢!请更新您的答案,以便我接受:)
【解决方案2】:

我想您绝对没有要求优化。虽然即使 那么,我会期望访问a 并访问b 来生成 完全相同的代码(至少在这种情况下)。

关于编译器如何知道:ab 有不同 类型,所以编译器知道用它们做不同的事情。这 标准的设计使得将int&amp;替换为int* const, 然后在每次访问时自动取消引用(除了 初始化)将导致一个一致的实现;它看起来 这就是你的编译器正在做的事情。

【讨论】:

  • int const* 不是指向常量整数的指针吗?你不是说int * const 吗?
  • @fjardon 是的。我已经修好了。谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2014-01-09
  • 2014-11-12
  • 1970-01-01
  • 2014-04-20
相关资源
最近更新 更多