2009-08-18 7 views
6

Tôi cần biết liệu khi một phương thức lớp trong C++ được gọi, thì con trỏ 'this' ẩn này là đối số đầu tiên, hoặc đối số cuối cùng. ví dụ: cho dù nó được đẩy lên ngăn xếp trước hay cuối cùng.C++ ngụ ý điều này, và chính xác cách nó được đẩy lên ngăn xếp

Nói cách khác, tôi đang hỏi liệu một phương pháp học, được gọi là, được thực hiện bởi trình biên dịch là:

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

Bằng cách mở rộng do đó, và quan trọng hơn, đó cũng sẽ trả lời cho dù G ++ sẽ đẩy con trỏ này lần cuối hoặc đầu tiên, tương ứng. Tôi thẩm vấn google, nhưng tôi không tìm thấy nhiều.

Và như một lưu ý phụ, khi các hàm C++ được gọi, chúng có thực hiện tương tự như các hàm C không? tức là:

push ebp 
mov ebp, esp 

Tất cả trong tất cả: một phương thức lớp học có được gọi là như thế này không?

; 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 

Cảm ơn và có nhiều nghĩa vụ.

EDIT: để làm rõ mọi thứ, tôi đang sử dụng GCC/G ++ 4.3

+0

Sẽ nhanh hơn nếu bạn không hỏi câu hỏi này và chỉ xem xét lắp ráp được tạo bởi trình biên dịch của bạn. Tất cả đều có thiết bị chuyển mạch để xuất mã lắp ráp dưới dạng văn bản. –

Trả lời

15

Điều này phụ thuộc vào quy ước gọi của trình biên dịch và kiến ​​trúc đích.

Theo mặc định, Visual C++ sẽ không đẩy điều này lên ngăn xếp. Đối với x86, trình biên dịch sẽ mặc định là "thiscall" gọi quy ước và sẽ vượt qua điều này trong sổ đăng ký ecx. Nếu bạn chỉ định __stdcall cho hàm thành viên của bạn, nó sẽ được đẩy lên ngăn xếp làm tham số đầu tiên.

Đối với x64 trên VC++, bốn thông số đầu tiên được chuyển vào sổ đăng ký. Đây là tham số đầu tiên và được chuyển vào thanh ghi rcx.

Raymond Chen đã có một chuỗi cách đây vài năm về các quy ước gọi điện. Dưới đây là các bài viết x86x64.

+0

http://en.wikipedia.org/wiki/X86_calling_conventions – Havenard

+0

Cảm ơn. Bài báo của Raymond Chen đã giải thích cho tôi. Tất cả là tốt nhất. –

1

Loại chi tiết này không được chỉ định theo tiêu chuẩn C++. Tuy nhiên, đọc qua C++ ABI cho gcc (và các trình biên dịch C++ khác theo sau C++ ABI).

8

này sẽ phụ thuộc vào trình biên dịch và kiến ​​trúc của bạn, nhưng trong G ++ 4.1.2 trên Linux không có các thiết lập tối ưu hóa nó đối xử với this như tham số đầu tiên, thông qua trong một thanh ghi:

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

Tháo lắp 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 
+0

Cảm ơn.Điều này cực kỳ hữu ích. –

2

tôi chỉ có một chi của ++ chuẩn C (ANSI ISO IEC 14882 2003), phần 9.3.2 "Con trỏ này", và nó dường như không chỉ định bất cứ điều gì về nơi mà nó sẽ xảy ra trong danh sách các đối số, do đó, nó tùy thuộc vào trình biên dịch riêng lẻ.

Hãy thử biên dịch một số mã bằng gcc bằng cờ '-S' để tạo mã lắp ráp và xem xét công việc đang làm.

+2

Nó thậm chí không xác định xem các đối số có nằm trên ngăn xếp hay không, hoặc thậm chí nếu có một ngăn xếp. – MSalters