8

我需要知道,当调用 C++ 中的类方法时,隐式“this”指针是第一个参数还是最后一个参数。即:是先入栈还是最后入栈。

换句话说,我问的是编译器是否将一个被调用的类方法视为:

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

因此,通过扩展,更重要的是,这也将回答 G++ 是否会分别最后或第一个推送 this 指针。我询问了谷歌,但我没有找到太多。

附带说明一下,当调用 C++ 函数时,它们的作用与 C 函数相同吗?IE:

push ebp
mov ebp, esp

总而言之:被调用的类方法会像这样吗?

; 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

谢谢,非常感谢。

编辑:为了澄清事情,我使用的是 GCC/G++ 4.3

4

4 回答 4

15

这取决于编译器的调用约定和目标架构。

默认情况下,Visual C++ 不会将其压入堆栈。对于 x86,编译器将默认使用“thiscall”调用约定,并将 this 在 ecx 寄存器中传递。如果为成员函数指定 __stdcall,它将作为第一个参数压入堆栈。

对于 VC++ 上的 x64,前四个参数在寄存器中传递。这是第一个参数并在 rcx 寄存器中传递。

几年前,Raymond Chen 有一个关于调用约定的系列。这是x86x64文章。

于 2009-08-19T00:02:32.460 回答
9

这将取决于您的编译器和架构,但在没有优化设置的 Linux 上的 G++ 4.1.2 中,它被视为this第一个参数,在寄存器中传递:

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;
}

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
于 2009-08-19T00:08:25.150 回答
2

我刚刚阅读了 C++ 标准(ANSI ISO IEC 14882 2003),第 9.3.2 节“this 指针”,它似乎没有指定任何关于它应该出现在参数列表中的位置,所以它取决于单独的编译器。

尝试使用'-S'标志用gcc编译一些代码来生成汇编代码并看看它在做什么。

于 2009-08-19T00:13:11.087 回答
1

C++ 标准没有规定这种细节。但是,请通读 gcc 的C++ ABI(以及遵循 C++ ABI 的其他 C++ 编译器)。

于 2009-08-19T00:04:04.377 回答