stdcall,__cdecl,_cdecl,_stdcall,__fastcall,_fastcall 區(qū)別簡介_第1頁
stdcall,__cdecl,_cdecl,_stdcall,__fastcall,_fastcall 區(qū)別簡介_第2頁
stdcall,__cdecl,_cdecl,_stdcall,__fastcall,_fastcall 區(qū)別簡介_第3頁
stdcall,__cdecl,_cdecl,_stdcall,__fastcall,_fastcall 區(qū)別簡介_第4頁
stdcall,__cdecl,_cdecl,_stdcall,__fastcall,_fastcall 區(qū)別簡介_第5頁
已閱讀5頁,還剩2頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、_stdcall,_cdecl,_cdecl,_stdcall,_fastcall,_fastcall 區(qū)別簡介C+/VC/C# 2008-03-16 13:05:51 閱讀1542 評論1 字號:大中小訂閱 1.今天寫線程函數(shù)時,發(fā)現(xiàn)msdn中對ThreadProc的定義有要求:DWORD WINAPI ThreadProc(LPVOID lpParameter); 不解為什么要用WINAPI宏定義,查了后發(fā)現(xiàn)下面的定義。于是乎需要區(qū)別_stdcall和_cdecl兩者的區(qū)別; #define CALLBACK _stdcall#define WINAPI _stdcall#define W

2、INAPIV _cdecl#define APIENTRY WINAPI#define APIPRIVATE _stdcall#define PASCAL _stdcall#define cdecl _cdecl#ifndef CDECL#define CDECL _cdecl#endif 幾乎我們寫的每一個WINDOWS API函數(shù)都是_stdcall類型的,首先,需要了解兩者之間的區(qū)別: WINDOWS的函數(shù)調(diào)用時需要用到棧(STACK,一種先入后出的存儲結(jié)構(gòu))。當(dāng)函數(shù)調(diào)用完成后,棧需要清楚,這里就是問題的關(guān)鍵,如何清除? 如果我們的函數(shù)使用了_cdecl,那么棧的清除工作是由調(diào)用者,用C

3、OM的術(shù)語來講就是客戶來完成的。這樣帶來了一個棘手的問題,不同的編譯器產(chǎn)生棧的方式不盡相同,那么調(diào)用者能否正常的完成清除工作呢?答案是不能。 如果使用_stdcall,上面的問題就解決了,函數(shù)自己解決清除工作。所以,在跨(開發(fā))平臺的調(diào)用中,我們都使用_stdcall(雖然有時是以WINAPI的樣子出現(xiàn))。那么為什么還需要_cdecl呢?當(dāng)我們遇到這樣的函數(shù)如fprintf()它的參數(shù)是可變的,不定長的,被調(diào)用者事先無法知道參數(shù)的長度,事后的清除工作也無法正常的進(jìn)行,因此,這種情況我們只能使用_cdecl。到這里我們有一個結(jié)論,如果你的程序中沒有涉及可變參數(shù),最好使用_stdcall關(guān)鍵字。2

4、._cdecl,_stdcall是聲明的函數(shù)調(diào)用協(xié)議.主要是傳參和彈棧方面的不同.一般c+用的是_cdecl,windows里大都用的是_stdcall(API) _cdecl是C/C+和MFC程序默認(rèn)使用的調(diào)用約定,也可以在函數(shù)聲明時加上_cdecl關(guān)鍵字來手工指定。采用_cdecl約定時,函數(shù)參數(shù)按照從右到左的順序入棧,并且由調(diào)用函數(shù)者把參數(shù)彈出棧以清理堆棧。因此,實(shí)現(xiàn)可變參數(shù)的函數(shù)只能使用該調(diào)用約定。由于每一個使用_cdecl約定的函數(shù)都要包含清理堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會比較大。_cdecl可以寫成_cdecl。 _stdcall調(diào)用約定用于調(diào)用Win32 API函數(shù)。采用

5、_stdcall約定時,函數(shù)參數(shù)按照從右到左的順序入棧,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的棧,函數(shù)參數(shù)個數(shù)固定。由于函數(shù)體本身知道傳進(jìn)來的參數(shù)個數(shù),因此被調(diào)用的函數(shù)可以在返回前用一條ret n指令直接清理傳遞參數(shù)的堆棧。_stdcall可以寫成_stdcall。 _fastcall約定用于對性能要求非常高的場合。_fastcall約定將函數(shù)的從左邊開始的兩個大小不大于4個字節(jié)(DWORD)的參數(shù)分別放在ECX和EDX寄存器,其余的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的堆棧。_fastcall可以寫成_fastcall3._stdcall:_stdcall 調(diào)用約定相當(dāng)于1

6、6位動態(tài)庫中經(jīng)常使用的PASCAL調(diào)用約定。在32位的VC+5.0中PASCAL調(diào)用約定不再被支持(實(shí)際上它已被定義為_stdcall。除了_pascal外,_fortran和_syscall也不被支持),取而代之的是_stdcall調(diào)用約定。兩者實(shí)質(zhì)上是一致的,即函數(shù)的參數(shù)自右向左通過棧傳遞,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧,但不同的是函數(shù)名的修飾部分(關(guān)于函數(shù)名的修飾部分在后面將詳細(xì)說明)。_stdcall是Pascal程序的缺省調(diào)用方式,通常用于Win32 Api中,函數(shù)采用從右到左的壓棧方式,自己在退出時清空堆棧。VC將函數(shù)編譯后會在函數(shù)名前面加上下劃線前綴,在函數(shù)名后加上和參

7、數(shù)的字節(jié)數(shù)。_cdecl:_cdecl c調(diào)用約定, 按從右至左的順序壓參數(shù)入棧,由調(diào)用者把參數(shù)彈出棧。對于傳送參數(shù)的內(nèi)存棧是由調(diào)用者來維護(hù)的(正因?yàn)槿绱?,?shí)現(xiàn)可變參數(shù)的函數(shù)只能使用該調(diào)用約定)。另外,在函數(shù)名修飾約定方面也有所不同。_cdecl是C和C程序的缺省調(diào)用方式。每一個調(diào)用它的函數(shù)都包含清空堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會比調(diào)用_stdcall函數(shù)的大。函數(shù)采用從右到左的壓棧方式。VC將函數(shù)編譯后會在函數(shù)名前面加上下劃線前綴。是MFC缺省調(diào)用約定。_fastcall:_fastcall調(diào)用約定是人如其名,它的主要特點(diǎn)就是快,因?yàn)樗峭ㄟ^寄存器來傳送參數(shù)的(實(shí)際上,它用ECX和E

8、DX傳送前兩個雙字(DWORD)或更小的參數(shù),剩下的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧),在函數(shù)名修飾約定方面,它和前兩者均不同。_fastcall方式的函數(shù)采用寄存器傳遞參數(shù),VC將函數(shù)編譯后會在函數(shù)名前面加上前綴,在函數(shù)名后加上和參數(shù)的字節(jié)數(shù)。thiscall:thiscall僅僅應(yīng)用于C+成員函數(shù)。this指針存放于CX寄存器,參數(shù)從右到左壓。thiscall不是關(guān)鍵詞,因此不能被程序員指定。naked call:采用1-4的調(diào)用約定時,如果必要的話,進(jìn)入函數(shù)時編譯器會產(chǎn)生代碼來保存ESI,EDI,EBX,EBP寄存器,退出函數(shù)時則產(chǎn)生代碼恢復(fù)這些寄存器的

9、內(nèi)容。naked call不產(chǎn)生這樣的代碼。naked call不是類型修飾符,故必須和_declspec共同使用。另附:關(guān)鍵字 _stdcall、_cdecl和_fastcall可以直接加在要輸出的函數(shù)前,也可以在編譯環(huán)境的Setting.C/C+ Code Generation項(xiàng)選擇。當(dāng)加在輸出函數(shù)前的關(guān)鍵字與編譯環(huán)境中的選擇不同時,直接加在輸出函數(shù)前的關(guān)鍵字有效。它們對應(yīng)的命令行參數(shù)分別為/Gz、/Gd和/Gr。缺省狀態(tài)為/Gd,即_cdecl。要完全模仿PASCAL調(diào)用約定首先必須使用_stdcall調(diào)用約定,至于函數(shù)名修飾約定,可以通過其它方法模仿。還有一個值得一提的是WINAPI宏

10、,Windows.h支持該宏,它可以將出函數(shù)翻譯成適當(dāng)?shù)恼{(diào)用約定,在WIN32中,它被定義為_stdcall。使用WINAPI宏可以創(chuàng)建自己的APIs。名字修飾約定 1、修飾名(Decoration name) “C”或者“C+”函數(shù)在內(nèi)部(編譯和鏈接)通過修飾名識別。修飾名是編譯器在編譯函數(shù)定義或者原型時生成的字符串。有些情況下使用函數(shù)的修飾名是必要的,如在模塊定義文件里頭指定輸出“C+”重載函數(shù)、構(gòu)造函數(shù)、析構(gòu)函數(shù),又如在匯編代碼里調(diào)用“C”或“C+”函數(shù)等。 修飾名由函數(shù)名、類名、調(diào)用約定、返回類型、參數(shù)等共同決定。 2、名字修飾約定隨調(diào)用約定和編譯種類(C或C+)的不同而變化。函數(shù)名修

11、飾約定隨編譯種類和調(diào)用約定的不同而不同,下面分別說明。 a、C編譯時函數(shù)名修飾約定規(guī)則: _stdcall調(diào)用約定在輸出函數(shù)名前加上一個下劃線前綴,后面加上一個“”符號和其參數(shù)的字節(jié)數(shù),格式為_functionnamenumber。 _cdecl調(diào)用約定僅在輸出函數(shù)名前加上一個下劃線前綴,格式為_functionname。_fastcall調(diào)用約定在輸出函數(shù)名前加上一個“”符號,后面也是一個“”符號和其參數(shù)的字節(jié)數(shù),格式為functionnamenumber。 它們均不改變輸出函數(shù)名中的字符大小寫,這和PASCAL調(diào)用約定不同,PASCAL約定輸出的函數(shù)名無任何修飾且全部大寫。 b、C+編譯時

12、函數(shù)名修飾約定規(guī)則: _stdcall調(diào)用約定: 1、以“?”標(biāo)識函數(shù)名的開始,后跟函數(shù)名; 2、函數(shù)名后面以“YG”標(biāo)識參數(shù)表的開始,后跟參數(shù)表; 3、參數(shù)表以代號表示: 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-表示指針,后面的代號表明指針類型,如果相同類型的指針連續(xù)出現(xiàn),以“0”代替,一個“0”代表一次重復(fù); 4、參數(shù)表的第一項(xiàng)為該函數(shù)的返回值類型,其后依次為參數(shù)的數(shù)據(jù)類型,指針標(biāo)識在

13、其所指數(shù)據(jù)類型前; 5、參數(shù)表后以“Z”標(biāo)識整個名字的結(jié)束,如果該函數(shù)無參數(shù),則以“Z”標(biāo)識結(jié)束。 其格式為“?functionnameYG*Z”或“?functionnameYG*XZ”,例如 int Test1(char *var1,unsigned long)-“?Test1YGHPADKZ” void Test2() -“?Test2YGXXZ” _cdecl調(diào)用約定: 規(guī)則同上面的_stdcall調(diào)用約定,只是參數(shù)表的開始標(biāo)識由上面的“YG”變?yōu)椤癥A”。 _fastcall調(diào)用約定: 規(guī)則同上面的_stdcall調(diào)用約定,只是參數(shù)表的開始標(biāo)識由上面的“YG”變?yōu)椤癥I”。 VC+對

14、函數(shù)的省缺聲明是“_cedcl“,將只能被C/C+調(diào)用. CB在輸出函數(shù)聲明時使用4種修飾符號 /_cdecl cb的默認(rèn)值,它會在輸出函數(shù)名前加_,并保留此函數(shù)名不變,參數(shù)按照從右到左的順序依次傳遞給棧,也可以寫成_cdecl和cdecl形式。 /_fastcall 她修飾的函數(shù)的參數(shù)將盡肯呢感地使用寄存器來處理,其函數(shù)名前加,參數(shù)按照從左到右的順序壓棧; /_pascal 它說明的函數(shù)名使用Pascal格式的命名約定。這時函數(shù)名全部大寫。參數(shù)按照從左到右的順序壓棧; /_stdcall 使用標(biāo)準(zhǔn)約定的函數(shù)名。函數(shù)名不會改變。使用_stdcall修飾時。參數(shù)按照由右到左的順序壓棧,也可以是_

15、stdcall;VC+對函數(shù)的省缺聲明是_cedcl,將只能被C/C+調(diào)用. 注意:1、_beginthread需要_cdecl的線程函數(shù)地址,_beginthreadex和CreateThread需要_stdcall的線程函數(shù)地址。2、一般WIN32的函數(shù)都是_stdcall。而且在Windef.h中有如下的定義:#define CALLBACK _stdcall#define WINAPI _stdcall3、extern C _declspec(dllexport) int _cdecl Add(int a, int b); typedef int (_cdecl*FunPointer)

16、(int a, int b); 修飾符的書寫順序如上。4、extern C的作用:如果Add(int a, int b)是在c語言編譯器編譯,而在c+文件使用,則需要在c+文件中聲明:extern C Add(int a, int b),因?yàn)閏編譯器和c+編譯器對函數(shù)名的解釋不一樣(c+編譯器解釋函數(shù)名的時候要考慮函數(shù)參數(shù),這樣是了方便函數(shù)重載,而在c語言中不存在函數(shù)重載的問題),使用extern C,實(shí)質(zhì)就是告訴c+編譯器,該函數(shù)是c庫里面的函數(shù)。如果不使用extern C則會出現(xiàn)鏈接錯誤。一般象如下使用:#ifdef _cplusplus #define EXTERN_C extern C

17、#else#define EXTERN_C extern#endif#ifdef _cplusplus extern C#endif EXTERN_C int func(int a, int b); #ifdef _cplusplus #endif5、MFC提供了一些宏,可以使用AFX_EXT_CLASS來代替_declspec(DLLexport),并修飾類名,從而導(dǎo)出類,AFX_API_EXPORT來修飾函數(shù),AFX_DATA_EXPORT來修飾變量AFX_CLASS_IMPORT:_declspec(DLLexport)AFX_API_IMPORT:_declspec(DLLexport

18、)AFX_DATA_IMPORT:_declspec(DLLexport)AFX_CLASS_EXPORT:_declspec(DLLexport)AFX_API_EXPORT:_declspec(DLLexport)AFX_DATA_EXPORT:_declspec(DLLexport)AFX_EXT_CLASS:#ifdef _AFXEXT AFX_CLASS_EXPORT #elseAFX_CLASS_IMPORT6、DLLMain負(fù)責(zé)初始化(Initialization)和結(jié)束(Termination)工作,每當(dāng)一個新的進(jìn)程或者該進(jìn)程的新的線程訪問DLL時,或者訪問DLL的每一個進(jìn)程或者線程不再使用DLL或者結(jié)束時,都會調(diào)用DLLMain。但是,使用TerminateProcess或TerminateThread結(jié)束進(jìn)程或者線程,不會調(diào)用DLLMain。7、一個DLL在內(nèi)存中只有一個實(shí)例DLL程序和調(diào)用其輸出函數(shù)的程序的關(guān)系:1)、DLL與進(jìn)程、線程之間的關(guān)系DLL模塊被映射到調(diào)用它的進(jìn)程的虛擬地址

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論