return 值 Vs 参考(在汇编中)

return value Vs reference (in assembly)

在查看了有关该主题的几个问题(和答案)后,我在 Compiler Explorer.

中尝试了以下简单代码
#include <iostream>


class TwoInts
{
public:
    TwoInts( ) = default;

    const int& getAByRef( ) const;

    int getAByVal( ) const;

private:
    int a;
    int b;
};

const int& TwoInts::getAByRef( ) const
{
    return a;
}

int TwoInts::getAByVal( ) const
{
    return a;
}


int main( )
{
    TwoInts ti;

    const int& num1 { ti.getAByRef( ) };
    const int num2 { ti.getAByVal( ) };

    //std::cout << num1 << ' ' << num2 << '\n';
}

现在我看到为两个成员函数 getAByRefgetAByVal 生成了不同的代码:

TwoInts::getAByRef() const:
        mov     rax, rdi
        ret
TwoInts::getAByVal() const:
        mov     eax, DWORD PTR [rdi]
        ret

谁能解释一下这两条不同的汇编指令在做什么?

每个成员函数都获取 this 指针作为隐式第一个函数参数,正如 GCC 使用的 Itanium ABI(不要与 Itanium 体系结构混淆)所规定的那样。 thisrdi 寄存器中传递,一个值在 rax (eax) 寄存器中被 returned(如果它是微不足道的,这里是)根据 x86-64 System V ABI(参见下面 Peter Cordes 的评论)。

在第一种情况下,当您通过引用 return a 时,您实际上是在 return 获取 a 的地址。 a是第一个成员,所以它的地址与对象的地址相同,即this。因此,您只需将 rax 设置为 rdi

在第二种情况下,当您按值 return a 时,您需要进行实际的取消引用。这就是 DWORD PTR [rdi] 正在做的事情。 DWORD PTR 表示你想要获取 4 个字节 (sizeof(int)).

如果你把一些数据成员放在 a 之前,你会看到一个额外的偏移量添加到 rdi