函式呼叫
規範__cdecl
和__stdcall的區別
一目了然(**形式)
原作:葡萄架上的牽牛花
__cdecl
__stdcallc和
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
編譯開關可以幫你檢查堆疊問題。
我也是初學者,若有不對的地方、可以補充的地方,請指教。
謝謝。
(補充)組合語言視點的比較文章:
intel x86 function-call conventions - assembly view
函式呼叫規範 cdecl和
cdecl stdcallc 和c 程式的預設呼叫規範 為了使用這種呼叫規範,需要你明確的加上 stdcall 或winapi 文字。即 return type stdcallfunction name argument list 在被呼叫函式 callee 返回後,由呼叫方 caller 調整堆疊...
函式呼叫規範 cdecl和
原作 葡萄架上的牽牛花 cdecl stdcallc和 c 程式的預設呼叫規範 為了使用這種呼叫規範,需要你明確的加上 stdcall 或winapi 文字。即 return type stdcallfunction name argument list 在被呼叫函式 callee 返回後,由呼叫方...
函式呼叫規範 cdecl和
cdecl stdcall c和c 程式的預設呼叫規範 為了使用這種呼叫規範,需要你明確的加上 stdcall 或 winapi 文字。即 return type stdcallfunction name argument list 在被呼叫函式 callee 返回後,由呼叫方 caller 調整堆...