stdcall, cdecl, pascal 區別(轉載)

轉載自:http://www.cnblogs.com/lidabo/archive/2012/11/21/2781484.htmlhtml

stdcall, cdecl, pascal 區別函數

這三個參數都是告訴編譯器參數的傳遞約定,參數的傳遞約定是指參數的傳遞順序(從左到右仍是從右到左)和由誰來恢復堆棧指針(調用者或者是被調用者),在 Win16下有兩種約定: C 和 PASCAL。 spa

    C約定規定參數傳遞順序是從右到左,即最右邊的參數最早壓棧,由調用者恢復堆棧指針。指針

    PASCAL約定和C約定正好相反,它規定參數是從左向右傳遞,由被調用者恢復堆棧。htm

    STDCALL是C約定和PASCAL約定的混合體,它規定參數的傳遞是從右到左, 恢復堆棧的工做交由被調用者完成。Win32只用STDCALL約定, 但除了一個特例, 即: wsprintf。blog

    __stdcall 這是一種函數調用方式。 __stdcall方式函數的參數壓棧順序從右到左,是Pascal 缺省調用方式,一般用於win32 API中,本身在退出時清空棧。內存

    __stdcall將參數壓棧是按C語言的順序(從右到左),但與C語言不一樣的是它是由被調用者將參數從棧中清除,因此它的編譯文件比_cdecl小。開發

    __stdcall是Windows  API函數中默認的調用約定,VB、VFP等也採用這個約定。編譯器

    __cdecl是C語言採用的默認調用方法,對於傳送參數的內存棧倒是由調用者來維護的。實現可變參數的調用只能用該方法。是MFC的缺省調用參數。io

    __fastcall方式的函數採用寄存器傳遞參數,VC將函數編譯後會在函數名前面加上"@"前綴,在函數名後加上"@"和參數的字節數。

 

調用約定           壓參數入棧順序     把參數彈出棧者         函數修飾名(Calling convention)
-------------------------------------------------------------------------
__cdecl              右->左                     調用者                          _function   
__fastcall           右->左                     被調用者                       @function@nnn    
__stdcall            右->左                     被調用者                      _function@nnn
__pascal           左->右                      被調用者                      _function@nnn
-------------------------------------------------------------------------

 

以上幾個關鍵詞可在「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。

相關文章
相關標籤/搜索