1. 程式人生 > >參數傳遞方法(用Delphi的匯編代碼解釋)

參數傳遞方法(用Delphi的匯編代碼解釋)

但是 大小 c++ 回調 程序 字符串類 string類 vcl 調用

李緯的InsideVCL《第一章》中提到Windows定義的回調函數

typedef LRESULT (CALLBACK*WNDPROC)(HWND,UNIT,WPARAM,LPARAM)

為了加快回調函數執行的效率,Microsoft使用了CALLBACK修飾關鍵詞來定義WNDPROC,而CALLBACK則是定義成FAR PASCAL.

那麽為什麽FARPASCAL就會更快執行呢?以下為我的解釋

(1)cdecl:

通常是C/C++所使用缺省的參數傳遞方式,它的傳遞方式是由右到左,而且當被調用的函數結束之後,將會由調用函數本身來清除堆棧上的參數數據。每一個調用它的函數都包含清空堆棧的代碼,所以產生的可執行文件大小會比調用_stdcall函數的大。

(2)stdcall:

參數傳遞方式,也是由右到左,但是當被調用的函數結束之後,則是由被調用函數來清除堆棧上的參數數據,Win32API所有的輸出函數都是采用此中參數傳遞方式

(3)pascal:

是Delphi1.0與win16API所使用的參數傳遞方式,它的傳遞方式是由左到右,而且由被調用函數來清除堆棧上的參數數據.

(4)fastcall:(delphi下關鍵字為register)

是Delphi默認所使用的參數傳遞方式, 主要特點就是快,因為它是通過寄存器來傳送參數的(實際上,它用ECX和EDX傳送前兩個雙字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳送,被調用的函數在返回前清理傳送參數的內存棧)

註:所以在引用C++動態庫中的函數時,要註意參數的傳遞方式,一般使用stdcall.還要註意字符串類型,C++在傳遞字符串時,都是采用字符指針的類型(Char *),所以你在Delphi的程序中就必須使用PCHAR類型,而不是string類型.

(5)thiscall

僅僅應用於“C++”成員函數。this指針存放於CX/ECX寄存器中,參數從右到左壓。thiscall不是關鍵詞,因此不能被程序員指定。

(6)naked call。

當采用1-4的調用約定時,如果必要的話,進入函數時編譯器會產生代碼來保存ESI,EDI,EBX,EBP寄存器,退出函數時則產生代碼恢復這些寄存器的內容。(這些代碼稱作 prologand epilog code,一般,ebp,esp的保存是必須的).但是naked call不產生這樣的代碼。naked call不是類型修飾符,故必須和_declspec共同使用。

匯編測試

其實。你只要寫一段下去測試。看它的 asm 就知道了。

1.觸發代碼

TForm1.Test1Click(1,2, 3);

begin

0044E298 6A03 push$03

0044E29A 6A02 push$02

0044E29C 6A01 push$01

0044E29E 50 pusheax

0044E29F E8D4FFFFFF call TForm1.Test1

end

0044E2A4 C3 ret

0044E2A5 8D4000 lea eax,[eax+$00]

TForm1.Test2Click(1,2, 3);

begin

0044E287 6A03 push $03

0044E289 B902000000 mov ecx,$00000002

0044E28E BA01000000 mov edx,$00000001

0044E293 8BC3 mov eax,ebx

0044E295 E8CEFFFFFF call TForm1.Test2

end

0044E2B9 C3 ret

0044E2BA 8BC0 mov eax,eax

2.函數源碼

FunctionTForm1.Test1(a, b, c: Integer): Integer; stdcall;

Begin

0044E268 55 push ebp

0044E269 8BEC mov ebp,esp

Result := a + b + c;

0044E25B 8B450C mov eax,[ebp+$0c]

0044E25E 034510 add eax,[ebp+$10]

0044E261 034514 add eax,[ebp+$14]

end

0044E264 5D pop ebp

0044E265 C21000 ret $0010

FunctionTForm1.Test2(a, b, c: Integer): Integer; register;

Begin

0044E268 55 push ebp

0044E269 8BEC mov ebp,esp

Result := a + b + c;

0044E26B 8D0411 lea eax,[ecx+edx]

0044E26E 034508 add eax,[ebp+$08]

end

0044E271 5D pop ebp

0044E272 C20400 ret $0004

0044E275 8D4000 lea eax,[eax+$00]

這樣看起來。是不是就有所差別了?

參數傳遞方法(用Delphi的匯編代碼解釋)