__cdecl?是C DECLaration的縮寫(declaration,聲明),表示C語言默認的函數調用方法:所有參數從右到左依次入棧,這些參數由調用者清除,稱為手動清棧。被調用函數不會要求調用者傳遞多少參數,調用者傳遞過多或者過少的參數,甚至完全不同的參數都不會產生編譯階段的錯誤。
?
_stdcall?是StandardCall的縮寫,是C++的標準調用方式:所有參數從右到左依次入棧,如果是調用類成員的話,最后一個入棧的是this指針。這些堆棧中的參數由被調用的函數在返回時清除,使用的指令是 retnX,X表示參數占用的字節數,CPU在ret之后自動彈出X個字節的堆棧空間。稱為自動清棧。函數在編譯的時候就必須確定參數個數,并且調用者必須嚴格的控制參數的生成,不能多,不能少,否則返回后會出錯。
?
_fastcall?是編譯器指定的快速調用方式。由于大多數的函數參數個數很少,使用堆棧傳遞比較費時。因此_fastcall通常規定將前兩個(或若干個)參數由寄存器傳遞,其余參數還是通過堆棧傳遞。不同編譯器編譯的程序規定的寄存器不同。返回方式和_stdcall相當。
?
?
?__thiscall?是為了解決類成員調用中this指針傳遞而規定的。__thiscall要求把this指針放在特定寄存器中,該寄存器由編譯器決定。VC使用ecx,Borland的C++編譯器使用eax。返回方式和_stdcall相當。
?
?
_fastcall?和?__thiscall涉及的寄存器由編譯器決定,因此不能用作跨編譯器的接口。所以Windows上的COM對象接口都定義為_stdcall調用方式。
?
?
| 調用類型 | 參數入棧順序 | 由誰負責清棧 | 寄存器傳遞 |
| __stdecl | 從右到左依次入棧 | 調用函數 | this |
| _stdcall? | 從右到左依次入棧 | 被調用函數 | this |
| _fastcall | 從右到左依次入棧 | 被調用函數 | this??和參數 |
| __thiscall | 從右到左依次入棧 | 被調用函數 | this |
| 默認(vs2005) | 從右到左依次入棧 | 被調用函數 | this |
?
?
?
?
?
?
?
?
下面來通過代碼來查看一下他們到底是如何傳遞參數和出入棧:
?
?
[cpp]?view plaincopyprint?
class?TestCallType??{??public:??????int?default_call(int?,int);??????int?__cdecl?????__cdecl_call(int?a,?int?b);??????int?_stdcall????_stdcall_call(int?a,?int?b);??????int?_fastcall???_fastcall_call(int?a,?int?b);??????int?__thiscall??_thiscall_call(int,int);??????int?x;??};??int?TestCallType::default_call(int?a,?int?b)??{??????this->x?=?a?+?b;??????return?this->x;??}??int?TestCallType::__cdecl_call(int?a,?int?b)??{??????this->x?=?a?+?b;??????return?this->x;??}??int?TestCallType::_stdcall_call(int?a,?int?b)??{??????this->x?=?a?+?b;??????return?this->x;??}??int?TestCallType::_fastcall_call(int?a,?int?b)??{??????this->x?=?a?+?b;??????return?this->x;??}??int?TestCallType::_thiscall_call(int?a,?int?b)??{??????this->x?=?a?+?b;??????return?this->x;??}??
?
?
調用的地方反匯編出來如下:
[cpp]?view plaincopyprint?
int?_tmain(int?argc,?_TCHAR*?argv[])??{??004115B0??push????????ebp????004115B1??mov?????????ebp,esp???004115B3??sub?????????esp,0CCh???004115B9??push????????ebx????004115BA??push????????esi????004115BB??push????????edi????004115BC??lea?????????edi,[ebp-0CCh]???004115C2??mov?????????ecx,33h???004115C7??mov?????????eax,0CCCCCCCCh???004115CC??rep?stos????dword?ptr?es:[edi]???????TestCallType?call_type;??????call_type.default_call(1,?2);??004115CE??push????????2??????????????????????/*?參數入棧?*/??004115D0??push????????1??????????????????????/*?參數入棧?*/??004115D2??lea?????????ecx,[call_type]????????/*?this指針?*/??004115D5??call????????TestCallType::default_call?(411113h)???????call_type.__cdecl_call(1,?2);??004115DA??push????????2?????????????????????/*?參數入棧?*/??004115DC??push????????1?????????????????????/*?參數入棧?*/??004115DE??lea?????????eax,[call_type]???????/*?this指針?*/??004115E1??push????????eax????004115E2??call????????TestCallType::__cdecl_call?(41112Ch)???004115E7??add?????????esp,0Ch???????????????/*?調用者負責清棧?*/??????call_type._fastcall_call(1,2);??004115EA??push????????2?????????????????????/*?參數入棧?*/??004115EC??mov?????????edx,1?????????????????/*?第一個參數通過寄存器傳遞?*/??004115F1??lea?????????ecx,[call_type]???????/*?this指針?*/??004115F4??call????????TestCallType::_fastcall_call?(41100Ah)???????call_type._stdcall_call(1,2);??004115F9??push????????2??????004115FB??push????????1??????004115FD??lea?????????eax,[call_type]???????/*?this指針?*/??00411600??push????????eax????00411601??call????????TestCallType::_stdcall_call?(4110EBh)???????call_type._thiscall_call(1,?2);??00411606??push????????2??????00411608??push????????1??????0041160A??lea?????????ecx,[call_type]???????/*?this指針?*/??0041160D??call????????TestCallType::_thiscall_call?(41117Ch)???????return?0;??0041161E??xor?????????eax,eax???}??
?
?
函數定義的地方反匯編:
[cpp]?view plaincopyprint?
int?TestCallType::default_call(int?a,?int?b)??{??004113D0??push????????ebp????004113D1??mov?????????ebp,esp???004113D3??sub?????????esp,0CCh???004113D9??push????????ebx????004113DA??push????????esi????004113DB??push????????edi????004113DC??push????????ecx????004113DD??lea?????????edi,[ebp-0CCh]???004113E3??mov?????????ecx,33h???004113E8??mov?????????eax,0CCCCCCCCh???004113ED??rep?stos????dword?ptr?es:[edi]???004113EF??pop?????????ecx????004113F0??mov?????????dword?ptr?[ebp-8],ecx???????this->x?=?a?+?b;??004113F3??mov?????????eax,dword?ptr?[a]???004113F6??add?????????eax,dword?ptr?[b]???004113F9??mov?????????ecx,dword?ptr?[this]???004113FC??mov?????????dword?ptr?[ecx],eax???????return?this->x;??004113FE??mov?????????eax,dword?ptr?[this]???00411401??mov?????????eax,dword?ptr?[eax]???}??00411403??pop?????????edi????00411404??pop?????????esi????00411405??pop?????????ebx????00411406??mov?????????esp,ebp???00411408??pop?????????ebp???????????????????/*?默認調用是_stdcall?被調用函數負責清棧?*/??00411409??ret?????????8??????---?No?source?file?-------------------------------------------------------------????int?TestCallType::__cdecl_call(int?a,?int?b)??{??00411420??push????????ebp????00411421??mov?????????ebp,esp???00411423??sub?????????esp,0C0h???00411429??push????????ebx????0041142A??push????????esi????0041142B??push????????edi????0041142C??lea?????????edi,[ebp-0C0h]???00411432??mov?????????ecx,30h???00411437??mov?????????eax,0CCCCCCCCh???0041143C??rep?stos????dword?ptr?es:[edi]???????this->x?=?a?+?b;??0041143E??mov?????????eax,dword?ptr?[a]???00411441??add?????????eax,dword?ptr?[b]???00411444??mov?????????ecx,dword?ptr?[this]???00411447??mov?????????dword?ptr?[ecx],eax???????return?this->x;??00411449??mov?????????eax,dword?ptr?[this]???0041144C??mov?????????eax,dword?ptr?[eax]???}??0041144E??pop?????????edi????0041144F??pop?????????esi????00411450??pop?????????ebx????00411451??mov?????????esp,ebp???00411453??pop?????????ebp????00411454??ret????????????????????????????/*?__cdecl?不用負責棧清除?*/??---?No?source?file?-------------------------------------------------------------????int?TestCallType::_stdcall_call(int?a,?int?b)??{??00411470??push????????ebp????00411471??mov?????????ebp,esp???00411473??sub?????????esp,0C0h???00411479??push????????ebx????0041147A??push????????esi????0041147B??push????????edi????0041147C??lea?????????edi,[ebp-0C0h]???00411482??mov?????????ecx,30h???00411487??mov?????????eax,0CCCCCCCCh???0041148C??rep?stos????dword?ptr?es:[edi]???????this->x?=?a?+?b;??0041148E??mov?????????eax,dword?ptr?[a]???00411491??add?????????eax,dword?ptr?[b]???00411494??mov?????????ecx,dword?ptr?[this]???00411497??mov?????????dword?ptr?[ecx],eax???????return?this->x;??00411499??mov?????????eax,dword?ptr?[this]???0041149C??mov?????????eax,dword?ptr?[eax]???}??0041149E??pop?????????edi????0041149F??pop?????????esi????004114A0??pop?????????ebx????004114A1??mov?????????esp,ebp???004114A3??pop?????????ebp????004114A4??ret?????????0Ch??????????????????//清除棧,字節數和參數入棧對應??---?No?source?file?-------------------------------------------------------------????int?TestCallType::_fastcall_call(int?a,?int?b)??{??004114C0??push????????ebp????004114C1??mov?????????ebp,esp???004114C3??sub?????????esp,0D8h???004114C9??push????????ebx????004114CA??push????????esi????004114CB??push????????edi????004114CC??push????????ecx????004114CD??lea?????????edi,[ebp-0D8h]???004114D3??mov?????????ecx,36h???004114D8??mov?????????eax,0CCCCCCCCh???004114DD??rep?stos????dword?ptr?es:[edi]???004114DF??pop?????????ecx????004114E0??mov?????????dword?ptr?[ebp-8],edx???004114E3??mov?????????dword?ptr?[ebp-14h],ecx???????this->x?=?a?+?b;??004114E6??mov?????????eax,dword?ptr?[a]???004114E9??add?????????eax,dword?ptr?[b]???004114EC??mov?????????ecx,dword?ptr?[this]???004114EF??mov?????????dword?ptr?[ecx],eax???????return?this->x;??004114F1??mov?????????eax,dword?ptr?[this]???004114F4??mov?????????eax,dword?ptr?[eax]???}??004114F6??pop?????????edi????004114F7??pop?????????esi????004114F8??pop?????????ebx????004114F9??mov?????????esp,ebp???004114FB??pop?????????ebp????004114FC??ret?????????4????????????????????//清除棧,字節數和參數入棧對應??---?No?source?file?-------------------------------------------------------------????int?TestCallType::_thiscall_call(int?a,?int?b)??{??00411510??push????????ebp????00411511??mov?????????ebp,esp???00411513??sub?????????esp,0CCh???00411519??push????????ebx????0041151A??push????????esi????0041151B??push????????edi????0041151C??push????????ecx????0041151D??lea?????????edi,[ebp-0CCh]???00411523??mov?????????ecx,33h???00411528??mov?????????eax,0CCCCCCCCh???0041152D??rep?stos????dword?ptr?es:[edi]???0041152F??pop?????????ecx????00411530??mov?????????dword?ptr?[ebp-8],ecx???????this->x?=?a?+?b;??00411533??mov?????????eax,dword?ptr?[a]???00411536??add?????????eax,dword?ptr?[b]???00411539??mov?????????ecx,dword?ptr?[this]???0041153C??mov?????????dword?ptr?[ecx],eax???????return?this->x;??0041153E??mov?????????eax,dword?ptr?[this]???00411541??mov?????????eax,dword?ptr?[eax]???}??00411543??pop?????????edi????00411544??pop?????????esi????00411545??pop?????????ebx????00411546??mov?????????esp,ebp???00411548??pop?????????ebp????00411549??ret?????????8???????????????????//清除棧,字節數和參數入棧對應??---?No?source?file?-------------------------------------------------------------??
總結
以上是生活随笔為你收集整理的函数调用方式__stdecl _stdcall _fastcall __thiscall介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。