WINAPI見windef.h這個頭檔案
#define WINAPI __stdcall
預設情況下,我們的函數調用都是遵循__stdcall這個規則的。當然,也有諸如__cdecl、__pascal等規則。
使用__stdcall還是__cdecl或__pascal,在純Windows程式設計下并非特别需要。
__stdcall:
1、進行函數調用,函數參數的入棧方式是最右邊先入棧。
2、同時__stdcall規定,調用者負責棧的回收。當然,這些工作是應用程式自己完成的,不需要編寫者動手。彙編語言另當别論(POP SP POP BP等)
題外話:__pascal的調用規則是從左到右,正好與__stdcall相反。
3、C調用約定(即用__cdecl關鍵字說明)(The C default calling convention)按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對于傳送參數的記憶體棧是由調用者來維護的(正因為如此,實作可變參數vararg的函數(如printf)隻能使用該調用約定)。另外,在函數名修飾約定方面也有所不同。 _cdecl是C和C++程式的預設調用方式。每一個調用它的函數都包含清空堆棧的代碼,是以産生的可執行檔案大小會比調用_stdcall函數的大。函數采用從右到左的壓棧方式。VC将函數編譯後會在函數名前面加上下劃線字首。
_stdcall 與 _cdecl 的差別
幾乎我們寫的每一個WINDOWS API函數都是__stdcall類型的,首先,需要了解兩者之間的差別: WINDOWS的函數調用時需要用到棧(STACK,一種先入後出的存儲結構)。當函數調用完成後,棧需要清除,這裡就是問題的關鍵,如何清除??如果我們的函數使用了_cdecl,那麼棧的清除工作是由調用者,用COM的術語來講就是客戶來完成的。這樣帶來了一個棘手的問題,不同的編譯器産生棧的方式不盡相同,那麼調用者能否正常的完成清除工作呢?答案是不能。如果使用__stdcall,上面的問題就解決了,函數自己解決清除工作。是以,在跨(開發)平台的調用中,我們都使用__stdcall(雖然有時是以WINAPI的樣子出現)。那麼為什麼還需要_cdecl呢?當我們遇到這樣的函數如 fprintf()它的參數是可變的,不定長的,被調用者事先無法知道參數的長度,事後的清除工作也無法正常的進行,是以,這種情況我們隻能使用 _cdecl。到這裡我們有一個結論,如果你的程式中沒有涉及可變參數,最好使用__stdcall關鍵字。