天天看點

__stdcall 和_cdecl 使用

  _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關鍵字.

繼續閱讀