long makefun(long lfun);
動態庫生成的時候採用的函式呼叫約定是__stdcall,所以編譯生成的a.dll中函式makefun的呼叫約定是_stdcall,也就是函式呼叫時引數從右向左入棧,函式返回時自己還原堆疊。現在某個程式模組b要引用a中的makefun,b和a一樣使用c++方式編譯,只是b模組的函式呼叫方式是__cdecl,由於b包含了a提供的標頭檔案中makefun函式宣告,所以makefun在b模組中被其它呼叫makefun的函式認為是__cdecl呼叫方式,b模組中的這些函式在呼叫完makefun當然要幫著恢復堆疊啦,可是makefun已經在結束時自己恢復了堆疊,b模組中的函式這樣多此一舉就引起了棧指標錯誤,從而引發堆疊異常。巨集觀上的現象就是函式呼叫沒有問題(因為引數傳遞順序是一樣的),makefun也完成了自己的功能,只是函式返回後引發錯誤。解決的方法也很簡單,只要保證兩個模組的在編譯時設定相同的函式呼叫約定就行了。
在了解了函式呼叫約定和函式的名修飾規則之後,再來看在c++程式中使用c語言編譯的庫時經常出現的lnk 2001錯誤就很簡單了。還以上面例子的兩個模組為例,這一次兩個模組在編譯的時候都採用__stdcall呼叫約定,但是a.dll使用c語言的語法編譯的(c語言方式),所以a.dll的載入庫a.lib中makefun函式的名字修飾就是
「_makefun@4
」。b包含了a提供的標頭檔案中makefun函式宣告,但是由於b採用的是c++語言編譯,所以makefun在b模組中被按照c++的名字修飾規則命名為「?makefu
n@@ygjj@z
」,編譯過程相安無事,鏈結程式時c++的鏈結器就到a.lib中去找
「?makefun@@ygjj@z
」,但是a.lib中只有「_ma
kefun@4
」,沒有
「?makefun@@ygjj@z
error lnk2001: unresolved external symbol
?makefun@@ygjj@z
解決的方法和簡單,就是要讓b模組知道這個函式是c語言編譯的,extern "c"可以做到這一點。乙個採用c語言編譯的庫應該考慮到使用這個庫的程式可能是c++程式(使用c++編譯器),所以在設計標頭檔案時應該注意這一點。通常應該這樣宣告標頭檔案:
#ifdef _cplusplus
extern "c"
#endif
這樣c++的編譯器就知道makefun的修飾名是
「_makefun@4
」,就不會有鏈結錯誤了。
許多人不明白,為什麼我使用的編譯器都是vc的編譯器還會產生「error lnk2001」錯誤?其實,vc的編譯器會根據原始檔的副檔名選擇編譯方式,如果檔案的副檔名是「.c」,編譯器會採用c的語法編譯,如果副檔名是「.cpp」,編譯器會使用c++的語法編譯程式,所以,最好的方法就是使用extern "c"。
函式呼叫約定與函式名稱修飾規則 VC
inte2000 163.com 使用c c 語言開發軟體的程式設計師經常碰到這樣的問題 有時候是程式編譯沒有問題,但是鏈結的時候總是報告函式不存在 經典的lnk 2001錯誤 有時候是程式編譯和鏈結都沒有錯誤,但是只要呼叫庫中的函式就會出現堆疊異常。這些現象通常是出現在c和c 的 混合使用的情況下...
函式呼叫約定與函式名稱修飾規則 舉例
public virtual long stdcall cbasefilter queryvendorinfo wchar t queryvendorinfo cbasefilter uagjpapa w z public thiscall cbasevideorenderer cbasevideo...
函式呼叫約定與函式名稱修飾規則(一)
e mail 使用c c 語言開發軟體的程式設計師經常碰到這樣的問題 有時候是程式編譯沒有問題,但是鏈結的時候總是報告函式不存在 經典的lnk 2001錯誤 有時候是程式編譯和鏈結都沒有錯誤,但是只要呼叫庫中的函式就會出現堆疊異常。這些現象通常是出現在c和c 的 混合使用的情況下或在c 程式中使用第...