函數調用規範__cdecl和__stdcall的區別一目瞭然(表格形式)(二)

 

__cdecl

 

 

__stdcall

 

C  C++ 程序的缺省調用規範

 

爲了使用這種調用規範,需要你明確的加上 __stdcall(或 WINAPI )文字。即 return-type __stdcallfunction-name [(argument-list )]

 

 

 調用函數 (Callee) 返回 ,由調用(Caller) 調整堆棧。

 

1. 調用方的函數調用

                                         

2. 調用函數的執行

 

3. 調用函數的結果返回

 

4. 調用方清除調整堆棧

                                                               

 

 調用函數 (Callee) 返回 ,由 調用函數(Callee) 調整堆棧。圖示:

 

1. 調用方的函數調用

 

2. 調用函數的執行

 

3. 調用函數清除調整堆棧

 

4. 調用函數的結果返回                                                         

 

因爲每個調用的地方都需要生成一段調整堆棧的代碼,所以最後生成的文件較大。

 

 

因爲調整堆棧的代碼只存在在一個地方(被調用函數的代碼內),所以最後生成的文件較小。

 

函數的參數個數可變(就像 printf 函數一樣),因爲只有調用者才知道它傳給被調用函數幾個參數,才能在調用結束時適當地調整堆棧。

 

 

函數的參數個數不能是可變的。

 

對於定義在 C 程序文件中的輸出函數函數名會保持原樣,不會被修飾。

對於定義在 C++ 程序文件中的輸出函數函數名會被修飾, MSDN  Underscore character (_) is prefixed to names 我實際測試( VC4  VC6 )下來發現好像不是那麼簡單。

可通過在前面加上 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 的線程函數地址

 

 

_beginthreadex  CreateThread 需要 __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 編譯開關可以幫你檢查堆棧問題。

我也是初學者,若有不對的地方、可以補充的地方,請指教。謝謝  

 

(http://blog.sina.com.cn/s/blog_6e9cb86f0100w8ev.html#)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章