調用約定_stdcall _cdecl _fastcall的區別
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的區別