_stdcall與_cdecl的差別 2007-06-13 15:57
_cdecl是C和C++程式的預設調用方式。每一個調用它的函數都包含清空堆棧的代碼, 是以産生的可執行檔案大小會比調用_stdcall函數的大。函數采用從右到左的壓棧方式 。VC将函數編譯後會在函數名前面加上下劃線字首。 _stdcall是Pascal程式的預設調用方式,通常用于Win32 Api中,函數采用從右到左的壓 棧方式,自己在退出時清空堆棧。VC将函數編譯後會在函數名前面加上下劃線字首,在 函數名後加上"@"和參數的位元組數。 _fastcall方式的函數采用寄存器傳遞參數,VC将函數編譯後會在函數名前面加上"@"前 綴,在函數名後加上"@"和參數的位元組數。 一篇文章from vckbase __stdcall和_cdecl (xulion發表于2001-8-21 10:28:16) [精彩文章] 這兩個關鍵字看起來似乎很少和我們打交道,但是看了下面的定義(來自windef.h ),你一定會覺得驚訝: #define CALLBACK __stdcall #define WINAPI __stdcall #define WINAPIV __cdecl #define APIENTRY WINAPI #define APIPRIVATE __stdcall #define PASCAL __stdcall #define cdecl _cdecl #ifndef CDECL #define CDECL _cdecl #endif 幾乎我們寫的每一個WINDOWS API函數都是__stdcall類型的,為什麼?? 首先,我們談一下兩者之間的差別: WINDOWS的函數調用時需要用到棧(STACK,一種先入後出的存儲結構)。當函數 調用完成後,棧需要清楚,這裡就是問題的關鍵,如何清除?? 如果我們的函數使用了_cdecl,那麼棧的清除工作是由調用者,用COM的術語來講 就是客戶來完成的。這樣帶來了一個棘手的問題,不同的編譯器産生棧的方式不盡相同 ,那麼調用者能否正常的完成清除工作呢?答案是不能。 如果使用__stdcall,上面的問題就解決了,函數自己解決清除工作。是以,在跨 (開發)平台的調用中,我們都使用__stdcall(雖然有時是以WINAPI的樣子出現)。 那麼為什麼還需要_cdecl呢?當我們遇到這樣的函數如fprintf()它的參數是可變 的,不定長的,被調用者事先無法知道參數的長度,事後的清除工作也無法正常的進行 ,是以,這種情況我們隻能使用_cdecl。 到這裡我們有一個結論,如果你的程式中沒有涉及可變參數,最好使用__stdcal l關鍵字. |