版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、_stdcall,_cdecl,_cdecl,_stdcall,_fastcall,_fastcall 區(qū)別簡(jiǎn)介C+/VC/C# 2008-03-16 13:05:51 閱讀1542 評(píng)論1 字號(hào):大中小訂閱 1.今天寫線程函數(shù)時(shí),發(fā)現(xiàn)msdn中對(duì)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 幾乎我們寫的每一個(gè)WINDOWS API函數(shù)都是_stdcall類型的,首先,需要了解兩者之間的區(qū)別: WINDOWS的函數(shù)調(diào)用時(shí)需要用到棧(STACK,一種先入后出的存儲(chǔ)結(jié)構(gòu))。當(dāng)函數(shù)調(diào)用完成后,棧需要清楚,這里就是問題的關(guān)鍵,如何清除? 如果我們的函數(shù)使用了_cdecl,那么棧的清除工作是由調(diào)用者,用C
3、OM的術(shù)語來講就是客戶來完成的。這樣帶來了一個(gè)棘手的問題,不同的編譯器產(chǎn)生棧的方式不盡相同,那么調(diào)用者能否正常的完成清除工作呢?答案是不能。 如果使用_stdcall,上面的問題就解決了,函數(shù)自己解決清除工作。所以,在跨(開發(fā))平臺(tái)的調(diào)用中,我們都使用_stdcall(雖然有時(shí)是以WINAPI的樣子出現(xiàn))。那么為什么還需要_cdecl呢?當(dāng)我們遇到這樣的函數(shù)如fprintf()它的參數(shù)是可變的,不定長(zhǎng)的,被調(diào)用者事先無法知道參數(shù)的長(zhǎng)度,事后的清除工作也無法正常的進(jìn)行,因此,這種情況我們只能使用_cdecl。到這里我們有一個(gè)結(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ù)聲明時(shí)加上_cdecl關(guān)鍵字來手工指定。采用_cdecl約定時(shí),函數(shù)參數(shù)按照從右到左的順序入棧,并且由調(diào)用函數(shù)者把參數(shù)彈出棧以清理堆棧。因此,實(shí)現(xiàn)可變參數(shù)的函數(shù)只能使用該調(diào)用約定。由于每一個(gè)使用_cdecl約定的函數(shù)都要包含清理堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會(huì)比較大。_cdecl可以寫成_cdecl。 _stdcall調(diào)用約定用于調(diào)用Win32 API函數(shù)。采用
5、_stdcall約定時(shí),函數(shù)參數(shù)按照從右到左的順序入棧,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的棧,函數(shù)參數(shù)個(gè)數(shù)固定。由于函數(shù)體本身知道傳進(jìn)來的參數(shù)個(gè)數(shù),因此被調(diào)用的函數(shù)可以在返回前用一條ret n指令直接清理傳遞參數(shù)的堆棧。_stdcall可以寫成_stdcall。 _fastcall約定用于對(duì)性能要求非常高的場(chǎng)合。_fastcall約定將函數(shù)的從左邊開始的兩個(gè)大小不大于4個(gè)字節(jié)(DWORD)的參數(shù)分別放在ECX和EDX寄存器,其余的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的堆棧。_fastcall可以寫成_fastcall3._stdcall:_stdcall 調(diào)用約定相當(dāng)于1
6、6位動(dòng)態(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ù)采用從右到左的壓棧方式,自己在退出時(shí)清空堆棧。VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線前綴,在函數(shù)名后加上和參
7、數(shù)的字節(jié)數(shù)。_cdecl:_cdecl c調(diào)用約定, 按從右至左的順序壓參數(shù)入棧,由調(diào)用者把參數(shù)彈出棧。對(duì)于傳送參數(shù)的內(nèi)存棧是由調(diào)用者來維護(hù)的(正因?yàn)槿绱?,?shí)現(xiàn)可變參數(shù)的函數(shù)只能使用該調(diào)用約定)。另外,在函數(shù)名修飾約定方面也有所不同。_cdecl是C和C程序的缺省調(diào)用方式。每一個(gè)調(diào)用它的函數(shù)都包含清空堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會(huì)比調(diào)用_stdcall函數(shù)的大。函數(shù)采用從右到左的壓棧方式。VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線前綴。是MFC缺省調(diào)用約定。_fastcall:_fastcall調(diào)用約定是人如其名,它的主要特點(diǎn)就是快,因?yàn)樗峭ㄟ^寄存器來傳送參數(shù)的(實(shí)際上,它用ECX和E
8、DX傳送前兩個(gè)雙字(DWORD)或更小的參數(shù),剩下的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的內(nèi)存棧),在函數(shù)名修飾約定方面,它和前兩者均不同。_fastcall方式的函數(shù)采用寄存器傳遞參數(shù),VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上前綴,在函數(shù)名后加上和參數(shù)的字節(jié)數(shù)。thiscall:thiscall僅僅應(yīng)用于C+成員函數(shù)。this指針存放于CX寄存器,參數(shù)從右到左壓。thiscall不是關(guān)鍵詞,因此不能被程序員指定。naked call:采用1-4的調(diào)用約定時(shí),如果必要的話,進(jìn)入函數(shù)時(shí)編譯器會(huì)產(chǎn)生代碼來保存ESI,EDI,EBX,EBP寄存器,退出函數(shù)時(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í),直接加在輸出函數(shù)前的關(guān)鍵字有效。它們對(duì)應(yīng)的命令行參數(shù)分別為/Gz、/Gd和/Gr。缺省狀態(tài)為/Gd,即_cdecl。要完全模仿PASCAL調(diào)用約定首先必須使用_stdcall調(diào)用約定,至于函數(shù)名修飾約定,可以通過其它方法模仿。還有一個(gè)值得一提的是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ù)定義或者原型時(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í)函數(shù)名修飾約定規(guī)則: _stdcall調(diào)用約定在輸出函數(shù)名前加上一個(gè)下劃線前綴,后面加上一個(gè)“”符號(hào)和其參數(shù)的字節(jié)數(shù),格式為_functionnamenumber。 _cdecl調(diào)用約定僅在輸出函數(shù)名前加上一個(gè)下劃線前綴,格式為_functionname。_fastcall調(diào)用約定在輸出函數(shù)名前加上一個(gè)“”符號(hào),后面也是一個(gè)“”符號(hào)和其參數(shù)的字節(jié)數(shù),格式為functionnamenumber。 它們均不改變輸出函數(shù)名中的字符大小寫,這和PASCAL調(diào)用約定不同,PASCAL約定輸出的函數(shù)名無任何修飾且全部大寫。 b、C+編譯時(shí)
12、函數(shù)名修飾約定規(guī)則: _stdcall調(diào)用約定: 1、以“?”標(biāo)識(shí)函數(shù)名的開始,后跟函數(shù)名; 2、函數(shù)名后面以“YG”標(biāo)識(shí)參數(shù)表的開始,后跟參數(shù)表; 3、參數(shù)表以代號(hào)表示: 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-表示指針,后面的代號(hào)表明指針類型,如果相同類型的指針連續(xù)出現(xiàn),以“0”代替,一個(gè)“0”代表一次重復(fù); 4、參數(shù)表的第一項(xiàng)為該函數(shù)的返回值類型,其后依次為參數(shù)的數(shù)據(jù)類型,指針標(biāo)識(shí)在
13、其所指數(shù)據(jù)類型前; 5、參數(shù)表后以“Z”標(biāo)識(shí)整個(gè)名字的結(jié)束,如果該函數(shù)無參數(shù),則以“Z”標(biāo)識(shí)結(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)識(shí)由上面的“YG”變?yōu)椤癥A”。 _fastcall調(diào)用約定: 規(guī)則同上面的_stdcall調(diào)用約定,只是參數(shù)表的開始標(biāo)識(shí)由上面的“YG”變?yōu)椤癥I”。 VC+對(duì)
14、函數(shù)的省缺聲明是“_cedcl“,將只能被C/C+調(diào)用. CB在輸出函數(shù)聲明時(shí)使用4種修飾符號(hào) /_cdecl cb的默認(rèn)值,它會(huì)在輸出函數(shù)名前加_,并保留此函數(shù)名不變,參數(shù)按照從右到左的順序依次傳遞給棧,也可以寫成_cdecl和cdecl形式。 /_fastcall 她修飾的函數(shù)的參數(shù)將盡肯呢感地使用寄存器來處理,其函數(shù)名前加,參數(shù)按照從左到右的順序壓棧; /_pascal 它說明的函數(shù)名使用Pascal格式的命名約定。這時(shí)函數(shù)名全部大寫。參數(shù)按照從左到右的順序壓棧; /_stdcall 使用標(biāo)準(zhǔn)約定的函數(shù)名。函數(shù)名不會(huì)改變。使用_stdcall修飾時(shí)。參數(shù)按照由右到左的順序壓棧,也可以是_
15、stdcall;VC+對(duì)函數(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+編譯器對(duì)函數(shù)名的解釋不一樣(c+編譯器解釋函數(shù)名的時(shí)候要考慮函數(shù)參數(shù),這樣是了方便函數(shù)重載,而在c語言中不存在函數(shù)重載的問題),使用extern C,實(shí)質(zhì)就是告訴c+編譯器,該函數(shù)是c庫里面的函數(shù)。如果不使用extern C則會(huì)出現(xiàn)鏈接錯(cuò)誤。一般象如下使用:#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)一個(gè)新的進(jìn)程或者該進(jìn)程的新的線程訪問DLL時(shí),或者訪問DLL的每一個(gè)進(jìn)程或者線程不再使用DLL或者結(jié)束時(shí),都會(huì)調(diào)用DLLMain。但是,使用TerminateProcess或TerminateThread結(jié)束進(jìn)程或者線程,不會(huì)調(diào)用DLLMain。7、一個(gè)DLL在內(nèi)存中只有一個(gè)實(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等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年沖擊鉆施工綠色施工評(píng)估合同3篇
- 二零二五年度體育健身場(chǎng)所承包經(jīng)營(yíng)合同范文4篇
- 二零二四年度學(xué)校醫(yī)務(wù)室藥品及醫(yī)療器械采購合同3篇
- 2025年度個(gè)人自建房施工合同工程驗(yàn)收標(biāo)準(zhǔn)合同3篇
- 二零二四年度幼兒園食堂安全服務(wù)合同2篇
- 2025年度拆除項(xiàng)目進(jìn)度款支付合同范本4篇
- 二零二五年度房地產(chǎn)項(xiàng)目開發(fā)與派遣公司銷售團(tuán)隊(duì)派遣合同4篇
- 2025版農(nóng)業(yè)種植技術(shù)服務(wù)與科技研發(fā)合作合同3篇
- 2025年度海外影視制作團(tuán)隊(duì)勞務(wù)派遣及版權(quán)協(xié)議2篇
- 二零二五年度農(nóng)業(yè)土地資源調(diào)查測(cè)繪合同4篇
- 2025-2030年中國(guó)草莓市場(chǎng)競(jìng)爭(zhēng)格局及發(fā)展趨勢(shì)分析報(bào)告
- 第二章《有理數(shù)的運(yùn)算》單元備課教學(xué)實(shí)錄2024-2025學(xué)年人教版數(shù)學(xué)七年級(jí)上冊(cè)
- 華為智慧園區(qū)解決方案介紹
- 奕成玻璃基板先進(jìn)封裝中試線項(xiàng)目環(huán)評(píng)報(bào)告表
- 廣西壯族自治區(qū)房屋建筑和市政基礎(chǔ)設(shè)施全過程工程咨詢服務(wù)招標(biāo)文件范本(2020年版)修訂版
- 人教版八年級(jí)英語上冊(cè)期末專項(xiàng)復(fù)習(xí)-完形填空和閱讀理解(含答案)
- 2024新版有限空間作業(yè)安全大培訓(xùn)
- GB/T 44304-2024精細(xì)陶瓷室溫?cái)嗔炎枇υ囼?yàn)方法壓痕(IF)法
- 年度董事會(huì)工作計(jì)劃
- 《退休不褪色余熱亦生輝》學(xué)校退休教師歡送會(huì)
- 02R112拱頂油罐圖集
評(píng)論
0/150
提交評(píng)論