After taking a look at a few questions (and answers) regarding this topic, I tried the below simple code in godbolt .
#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';
}
Now I see different codes generated for the two member functions getAByRef
and getAByVal
:
TwoInts::getAByRef() const:
mov rax, rdi
ret
TwoInts::getAByVal() const:
mov eax, DWORD PTR [rdi]
ret
I would appreciate it if someone could explain what those two different assembly instructions are doing?
Each member function gets this
pointer as an implicit argument. In ABI used by that particular compiler ( Itanium ABI , not to be confused with Itanium architecture), this
is passed as the first argument in the rdi
register and a value is returned (if it's trivial, and here it is) in the rax
( eax
) register.
In the first case, when you return a
by reference, you're actually returning an address of a
. a
is the first member, so its address is the same as that of the object, ie this
. Hence, you just set rax
to rdi
.
In the second case, when you return a
by value, you need to do actual dereferencing. That's what DWORD PTR [rdi]
is doing. DWORD PTR
means that you want to fetch 4 bytes ( sizeof(int)
).
If you put some data member before a
, you'll see an additional offset added to rdi
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.