C/C++ / 函数调用规则汇总
零、函數調用規則解決的問題
在參數傳遞中,有兩個重要的問題必須要明確說明:
在高級語言中,就是通過函數的調用方式來說明這兩個問題的。常見的調用方式有:
stdcall、cdecl、fastcall、thiscall、naked call
下面就分別介紹這幾種調用方式:
一、stdcall
stdcall 調用方式又被稱為 Pascal 調用方式。在 Microsoft C++ 系列的 C/C++ 編譯器中,使用 PASCAL 宏、WINAPI 宏和 CALLBACK 宏來指定函數的調用方式為 stdcall。
stdcall 調用方式的函數聲明為:
int _stdcall function(int a, int b);stdcall 的調用方式意味著:
- 參數從右向左一次壓入堆棧。
- 由被調用函數自己來恢復堆棧。
- 函數名自動加前導下劃線,后面緊跟著一個@,其后緊跟著參數的尺寸。
上面那個函數翻譯成匯編語言將變成:
push b 先壓入第二個參數 push a 再壓入第一個參數 call function 調用函數在編譯時,此函數的名字被翻譯為 _function@8 。
二、cdecl
cdecl 調用方式又稱為 C 調用方式,是 C 語言缺省的調用方式,它的語法為:
int function(int a, int b) // 不加修飾符就是C調用方式int _cdecl function(int a, int b) // 明確指定用C調用方式cdecl的調用方式決定了:
- 參數從右向左依次壓入堆棧。
- 由調用者恢復堆棧。
- 函數名自動加前導下劃線。
由于是由調用者來恢復堆棧,因此 C 調用方式允許函數的參數個數是不固定的,這是 C 語言的一大特色。
此方式的函數被翻譯為:
push b // 先壓入第二個參數 push a // 在壓入第一個參數 call funtion // 調用函數 add esp, 8 // 清理堆棧在編譯時,此方式的函數被翻譯成:_function 。
三、fastcall
fastcall 按照名字上理解就可以知道,它是一種快速調用方式。此方式的函數的第一個和第二個DWORD參數通過 ecx 和 edx 傳遞,后面的參數從右向左的順序壓入棧,被調用函數清理堆棧。
函數名修個規則同 stdcall 。
其聲明語法為:
int fastcall function(int a, int b);四、thiscall
thiscall 調用方式是唯一一種不能顯示指定的修飾符。它是 c++ 類成員函數缺省的調用方式。由于成員函數調用還有一個 this 指針,因此必須用這種特殊的調用方式。
thiscall調用方式意味著:
- 參數從右向左壓入棧。
- 如果參數個數確定,this 指針通過 ecx 傳遞給被調用者;如果參數個數不確定,this 指針在所有參數壓入棧后被壓入棧。
- 參數個數不定的,由調用者清理堆棧,否則由函數自己清理堆棧。
可以看到,對于參數個數固定的情況,它類似于 stdcall,不定時則類似于 cdecl。
五、naked call
是一種比較少見的調用方式,一般高級程序設計語言中不常見。數的聲明調用方式和實際調用方式必須一致,必然編譯器會產生混亂。
六、函數名字修改規則
1. C 編譯時函數名修飾約定規則:
- __stdcall 調用約定在輸出函數名前加上一個下劃線前綴,后面加上一個“@”符號和其參數的字節數,格式為 _function@8。
- __cdecl 調用約定僅在輸出函數名前加上一個下劃線前綴,格式為 _function。
- __fastcall 調用約定在輸出函數名前加上一個“@”符號,后面也是一個“@”符號和其參數的字節數,格式為 @function@8。
- 它們均不改變輸出函數名中的字符大小寫,這和 PASCAL 調用約定不同,PASCAL 約定輸出的函數名無任何修飾且全部大寫。
2. C++編譯時函數名修飾約定規則:
__stdcall調用約定:
(1)以“?”標識函數名的開始,后跟函數名;
(2)函數名后面以“@@YG”標識參數表的開始,后跟參數表;
(3)參數表以代號表示:
| 代號 | 實際類型 |
| X | void |
| D | char |
| E | unsigned char |
| F | short |
| H | int |
| I | unsigned int |
| J | long |
| K | unsigned long |
| M | float |
| N | double |
| _N | bool |
| PA | 指針 |
?
?
(4)參數表的第一項為該函數的返回值類型,其后依次為參數的數據類型,指針標識在其所指數據類型前;
(5)參數表后以“@Z”標識整個名字的結束,如果該函數無參數,則以“Z”標識結束。
其格式為“?functionname@@YG*****@Z”或“?functionname@@YG*XZ”,例如
int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z”void Test2() -----“?Test2@@YGXXZ”__cdecl 調用約定:
規則同上面的 _stdcall 調用約定,只是參數表的開始標識由上面的“@@YG”變為“@@YA”。
__fastcall 調用約定:
規則同上面的 _stdcall 調用約定,只是參數表的開始標識由上面的“@@YG”變為“@@YI”。
VC++ 對函數的省缺聲明是"__cedcl",將只能被 C/C++ 調用。
?
轉載于:https://blog.csdn.net/baidu_39511645/article/details/78225267
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的C/C++ / 函数调用规则汇总的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构与算法 / 默克尔树
- 下一篇: s3c2440移植MQTT