天天看點

參數傳遞方法

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

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

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

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

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

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

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

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

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

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

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

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

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

  0044E287 6A03            push $03

  0044E289 B902000000       mov ecx,$00000002

  0044E28E BA01000000      mov edx,$00000001

  0044E293 8BC3             mov eax,ebx

  0044E295 E8CEFFFFFF      call TForm1.Test2

0044E2B9 C3               ret

0044E2BA 8BC0            mov eax,eax

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]

0044E264 5D               pop ebp

0044E265 C21000           ret $0010

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

0044E269 8BEC             mov ebp,esp

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

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

0044E271 5D               pop ebp

0044E272 C20400           ret $0004

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

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