1. 程式人生 > >調用約定_stdcall _cdecl _fastcall的區別

調用約定_stdcall _cdecl _fastcall的區別

print 1.4 約束 this 常常 color cto 總結 strong

1.函數調用約定

函數的調用約定,顧名思義就是對函數調用的一個約束和規定(規範),描述了函數參數是怎麽傳遞和由誰清除堆棧的。它決定以下內容:

  (1) 函數參數的壓棧順序;

  (2) 由調用者還是被調用者把參數彈出棧;

  (3) 產生函數修飾名的方法;

在看C++ primer中就提到函數聲明包括:返回值類型,函數名,形參列表

int function();
int add(int a,int b);

上面的函數聲明方式是我們經常用到的,其實還有一部分就是調用約定,目前存在:_cdecl、_stdcall、_fastcall、_pascall、_thiscall、_vectorvcall。我們使用的較為廣泛的調用是_cedcl、_stdcall以及_fastcall。下面分別講述一下各個調用約定的含義。

1.1 _cdecl調用約定

  __cdecl 是 C Declaration 的縮寫,是C/C++和MFC的默認調用約定。其具有如下的特點:

  (1) 按從右至左的順序壓參數入棧;

  (2)由調用者把參數彈出棧;切記:對於傳送參數的內存棧是由調用者來維護的,返回值在EAX中。因此對於像printf這樣可變參數的函數必須用這種約定。

  (3)編譯器在編譯的時候對這種調用規則的函數生成修飾名的時候,在輸出函數名前加上一個下劃線前綴,格式為_function。如函數int add(int a, int b)的修飾名是_add。

1.2 _stdcall調用約定

  __stdcall是Standard Call的縮寫,是C++的標準調用方式,是微軟定義的標準,__stdcall通常用於Win32 API中(可查看WINAPI的定義)。

  (1)按從右至左的順序壓參數入棧

  (2)由被調用者把參數彈出棧。切記:函數自己在退出時清空堆棧,返回值在EAX中。

  (3)__stdcall調用約定在輸出函數名前加上一個下劃線前綴,後面加上一個“@”符號和其參數的字節數,格式為[email protected]。如函數int sub(int a, int b)的修飾名是[email protected]

1.3 _fastcall調用約定

  __fastcall調用的主要特點就是快,因為它是通過寄存器來傳送參數的。

  (1)實際上__fastcall用ECX和EDX傳送前兩個DWORD或更小的參數,剩下的參數仍自右向左

壓棧傳送,被調用的函數在返回前清理傳送參數的內存棧。

  (2)__fastcall調用約定在輸出函數名前加上一個“@”符號,後面也是一個“@”符號和其參數的字節數,格式為@[email protected],如double multi(double a, double b)的修飾名是@[email protected]。

  (3)__fastcall和__stdcall很象,唯一差別就是頭兩個參數通過寄存器傳送。註意通過寄存器傳送的兩個參數是從左向右的,即第1個參數進ECX,第2個進EDX,其他參數是從右向左的入棧,返回仍然通過EAX。

1.4 _thiscall調用約定

  __thiscall是C++類成員函數缺省的調用約定,但它沒有顯示的聲明形式。因為在C++類中,成員函數調用還有一個this指針參數,因此必須特殊處理,thiscall調用約定的特點:

  (1)參數入棧:參數從右向左入棧

  (2)this指針入棧:如果參數個數確定,this指針通過ecx傳遞給被調用者;如果參數個數不確定,this指針在所有參數壓棧後被壓入棧。

  (3)棧恢復:對參數個數不定的,調用者清理棧,否則函數自己清理棧。

2.總結

特點 _cdecl _stdcall _fastcall
參數傳遞方式 從右向左 從右向左 左邊開始的兩個不大於4字節(DWORD)的參數分別放在ECX和EDX寄存器,其余的參數自右向左壓棧傳送
清理棧方式  調用者清理 被調用函數清理 被調用函數清理
使用場合 C/C++、MFC的默認方式; 可變參數的時候使用; Win API 要求速度快
編譯修飾約定 _functionname [email protected] @[email protected]

  從代碼和程序調試的層面考慮,參數的壓棧順序和棧的清理我們都不用太觀註,因為這是編譯器的決定的,我們改變不了。但第三點卻常常困擾我們,因為如果不弄清楚這點,在多個庫之間(如dll、lib、exe)相互調用、依賴時常常出出現莫名其妙的錯誤

以上內容參考:http://blog.csdn.net/luoweifu/article/details/52425733

調用約定_stdcall _cdecl _fastcall的區別