The C++ implicit this, and exactly how it is pushe

2019-04-24 16:23发布

问题:

I need to know whether, when a class method in C++ is called, the implicit 'this' pointer is the first argument, or the last. i.e: whether it is pushed onto the stack first or last.

In other words, I'm asking whether a class method, being called, is taken by the compiler to be:

int foo::bar(foo *const this, int arg1, int arg2); 
//or:
int foo::bar(int arg1, int arg2, foo *const this);

By extension therefore, and more importantly, that would also answer whether G++ would push the this pointer last or first, respectively. I interrogated google, but I didn't find much.

And as a side note, when C++ functions are called, do they do the same thing as C functions? i.e:

push ebp
mov ebp, esp

All in all: would a class method being called look like this?

; About to call foo::bar.
push dword 0xDEADBEEF
push dword 0x2BADBABE
push dword 0x2454ABCD ; This one is the this ptr for the example.
; this code example would match up if the this ptr is the first argument.
call _ZN3foo3barEpjj

Thanks, and much obliged.

EDIT: to clarify things, I'm using GCC/G++ 4.3

回答1:

This depends on the calling convention of your compiler and the target architecture.

By default, Visual C++ will not push this on the stack. For x86, the compiler will default to "thiscall" calling convention and will pass this in the ecx register. If you specify __stdcall for you member function, it will be pushed on the stack as the first parameter.

For x64 on VC++, the first four parameters are passed in registers. This is the first parameter and passed in the rcx register.

Raymond Chen had a series some years ago on calling conventions. Here are the x86 and x64 articles.



回答2:

This will depend on your compiler and architecture, but in G++ 4.1.2 on Linux with no optimization settings it treats this as the first parameter, passed in a register:

class A
{
public:
    void Hello(int, int) {}
};

void Hello(A *a, int, int) {}

int main()
{
    A a;
    Hello(&a, 0, 0);
    a.Hello(0, 0);
    return 0;
}

Disassembly of main():

movl    $0, 8(%esp)
movl    $0, 4(%esp)
leal    -5(%ebp), %eax
movl    %eax, (%esp)
call    _Z5HelloP1Aii

movl    $0, 8(%esp)
movl    $0, 4(%esp)
leal    -5(%ebp), %eax
movl    %eax, (%esp)
call    _ZN1A5HelloEii


回答3:

I just had a read of the C++ Standard (ANSI ISO IEC 14882 2003), section 9.3.2 "The this pointer", and it does not seem to specify anything about where it should occur in the list of arguments, so it's up to the individual compiler.

Try compiling some code with gcc using the '-S' flag to generate assembly code and take a look at what it's doing.



回答4:

This sort of detail is not specified by the C++ standard. However, read through the C++ ABI for gcc (and other C++ compilers that follow the C++ ABI).