__cdecl和__stdcall的區別

 
Posted on Tuesday, May 24, 2005 3:23 PM #C & C++
 
__cdecl
 
 
__stdcall
 
CC++程序的缺省調用規範
 
爲了使用這種調用規範,需要你明確的加上__stdcall(或WINAPI)文字。即return-type __stdcall function-name[(argument-list)]
 
 
調用函數(Callee)返回,由調用者(Caller)調整堆棧。
 
調用者
    // call function
    // adjust stack
 
被調用函數
    // do work
    // return
 
調用函數(Callee)返回,由調用函數(Callee)調整堆棧。圖示:
 
調用者
    // call function
 
被調用函數
    // do work
    // adjust stack
    // return
 
因爲每個調用的地方都需要生成一段調整堆棧的代碼,所以最後生成的文件較大。
 
 
因爲調整堆棧的代碼只存在在一個地方(被調用函數的代碼內),所以最後生成的文件較小。
 
函數的參數個數可變(就像printf函數一樣),因爲只有調用者才知道它傳給被調用函數幾個參數,才能在調用結束時適當地調整堆棧。
 
 
函數的參數個數不能是可變的。
 
對於定義在C程序文件中的輸出函數,函數名會保持原樣,不會被修飾。
對於定義在C++程序文件中的輸出函數,函數名會被修飾, MSDNUnderscore character (_) is prefixed to names. 我實際測試(VC4VC6)下來發現好像不是那麼簡單。
可通過在前面加上extern “C”以去除函數名修飾。也可通過.def文件去除函數名修飾。
 
不論是C程序文件中的輸出函數還是C++程序文件中的輸出函數,函數名都會被修飾。
對於定義在C程序文件中的輸出函數,An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list.
對於定義在C++程序文件中的輸出函數,好像更復雜,和__cdecl的情況類似。
好像只能通過.def文件去除函數名修飾。
 
 
_beginthread需要__cdecl的線程函數地址
 
 
_beginthreadexCreateThread需要__stdcall的線程函數地址
 
 
兩者的參數傳遞順序都是從右向左。
爲了讓VB可以調用,需要用__stdcall調用規範來定義C/C++函數。請參看Microsoft KB153586 文章:How To Call C Functions That Use the _cdecl Calling Convention
當你LoadLibrary一個DLL文件後, 把GetProcAddress取得的函數地址傳給上面三個線程生成函數時,請務必確認實際定義在DLL文件的輸出函數符合調用規範要求。否則,編譯成Release版後運行,可能會破壞堆棧,程序行爲不可預測。
VC中的相關編譯開關:/Gd /Gr /Gz。另外,VC6中新增加的 /GZ 編譯開關可以幫你檢查堆棧問題。
我也是初學者,若有不對的地方、可以補充的地方,請指教。謝謝。 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章