轉自:點擊打開鏈接
(1) _stdcall調用
_stdcall是Pascal程序的缺省調用方式,參數採用從右到左的壓棧方式,被調函數自身在返回前清空堆棧。
WIN32 Api都採用_stdcall調用方式,這樣的宏定義說明了問題:
#define WINAPI _stdcall
按C編譯方式,_stdcall調用約定在輸出函數名前面加下劃線,後面加“@”符號和參數的字節數,形如。
(2) _cdecl調用
_cdecl是C/C++的缺省調用方式,參數採用從右到左的壓棧方式,傳送參數的內存棧由調用者維護。_cedcl約定的函數只能被C/C++調用,每一個調用它的函數都包含清空堆棧的代碼,所以產生的可執行文件大小會比調用_stdcall函數的大。
由於_cdecl調用方式的參數內存棧由調用者維護,所以變長參數的函數能(也只能)使用這種調用約定。關於C/C++中變長參數(…)的問題,筆者將另文詳述。
由於Visual C++默認採用_cdecl 調用方式,所以VC中中調用DLL時,用戶應使用_stdcall調用約定。
按C編譯方式,_cdecl調用約定僅在輸出函數名前面加下劃線,形如_functionname。
(3) _fastcall調用
_fastcall調用較快,它通過CPU內部寄存器傳遞參數。
按C編譯方式,_fastcall調用約定在輸出函數名前面加“@”符號,後面加“@”符號和參數的字節數,形如@functionname@number。
首先,我們談一下兩者之間的區別:
WINDOWS的函數調用時需要用到棧(STACK,一種先入後出的存儲結構)。當函數
調用完成後,棧需要清除,這裏就是問題的關鍵,如何清除??
如果我們的函數使用了_cdecl,那麼棧的清除工作是由調用者,用COM的術語來講
就是客戶來完成的。這樣帶來了一個棘手的問題,不同的編譯器產生棧的方式不盡相同
,那麼調用者能否正常的完成清除工作呢?答案是不能。
如果使用__stdcall,上面的問題就解決了,函數自己解決清除工作。所以,在跨
(開發)平臺的調用中,我們都使用__stdcall(雖然有時是以WINAPI的樣子出現)。
那麼爲什麼還需要_cdecl呢?當我們遇到這樣的函數如fprintf()它的參數是可變
的,不定長的,被調用者事先無法知道參數的長度,事後的清除工作也無法正常的進行
,因此,這種情況我們只能使用_cdecl。
到這裏我們有一個結論,如果你的程序中沒有涉及可變參數,最好使用__stdcal
l關鍵字