所謂名字修飾約定,就是指變數名、函式名等經過編譯後重新輸出名稱的規則。
比如源**中函式名稱為int func(int a,int b),經過編譯後名稱可能為?func@@yahhh@z、?func@@yghhh@z、_func@8,也有可能與源**中名稱相同為func。
影響編譯後輸出的名稱通常與名字修飾約定(extern "c"、extern "c++"等)和函式呼叫約定(__stdcall、__cdecl等)等相關。
口說千遍,不如實際演練一遍。那麼,就讓我們寫**來測試下。
注意,本文只討論extern "c"、extern "c++"和__stdcall、__cdecl相關的約定,其他約定不在本文討論範圍內。另外,編譯的環境為xp + vc++6.0sp6。
首先,用c方式匯出兩個函式:
dll1.c
_declspec(dllexport) int __cdecl func_cdecl(int a,int b)
_declspec(dllexport) int __stdcall func_stdcall(int a,int b)
匯出的兩個函式名為:
再以c++方式匯出:
dll1.cpp
_declspec(dllexport) int __cdecl func_cdecl(int a,int b)
_declspec(dllexport) int __stdcall func_stdcall(int a,int b)
匯出結果如下:
然後,我們再以c++方式匯出如下**中的函式:
extern "c" _declspec(dllexport) int __stdcall func_c_stdcall(int a,int b)
extern "c++" _declspec(dllexport) int __stdcall func_cpp_stdcall(int a,int b)
extern "c" _declspec(dllexport) int __cdecl func_c_cdecl(int a,int b)
extern "c++" _declspec(dllexport) int __cdecl func_cpp_cdecl(int a,int b)
匯出結果如下
有了以上實驗結果,我們再結合以下名字輸出規則進行理解:
c方式編譯(extern "c"):
__stdcall呼叫約定:輸出名稱在原名稱前加一下劃線,後面再加上乙個「@」和其引數的總位元組數(_
原名稱@引數總位元組數),如名稱int func_c_stdcall(int a,int b)輸出為_func_c_stdcall@8;
__cdecl呼叫約定:與原名稱相同,如名稱int func_c_cdecl(int a,int b)輸出還是為func_c_cdecl;
c++方式編譯(extern "c++"):
__stdcall呼叫約定:
輸出名稱以「?」開始,後跟原名稱;
原名稱後再跟「@@yg」,後面再跟返回值代號和參數列代號,代號表示如下:
x--void ,
d--char,
e--unsigned char,
f--short,
h--int,
i--unsigned int,
j--long,
k--unsigned long,
m--float,
n--double,
_n--bool,
...pa--表示指標,後面的代號表明指標型別,如果相同型別的指標連續出現,以「0」代替,乙個「0」代表一次重複;
參數列後以「@z」標識整個名字的結束,如果該函式無引數,則以「z」標識結束。如名稱int func_cpp_stdcall(int a,int b)編譯後的輸出名稱為?func_cpp_stdcall@@yghhh@z。
__cdecl呼叫約定:與_stdcall呼叫約定基本一致,只是參數列的開始標識由上面的「@@yg」變為「@@ya」。如名稱int func_cpp_cdecl(int a,int b)編譯後輸出名稱為?func_cpp_cdecl@@yahhh@z。
有個這個規則,再回頭去看我們的實驗結果,就很好理解了。
當然,編譯c檔案和編譯cpp檔案,不需加extern "c"和extern "c++",因為編譯c檔案當然預設的是extern "c",而編譯cpp檔案則預設的是extern "c++"。
現在我們也能理解為什麼匯出dll時通常需要加上extern "c"。試想,如果乙個c++匯出的dll,沒有加extern "c",則匯出的名稱為extern "c++"約定下的名稱。如果這個dll需要提供給用c編寫的程式使用,那麼這個程式是無法呼叫這個dll的,因為c寫的程式遵循的是extern "c"約定,鏈結時鏈結器將按照extern "c"約定的名稱去尋找外部名稱,這當然找不到,因為dll中的輸出名稱為extern "c++"約定下的名稱。
函式呼叫約定與名字修飾約定
在windows下,由於很多語言支援動態鏈結庫技術,因此動態鏈結庫是一種很好的混合程式設計方法。語言對函式的約定有兩種 函式呼叫約定和名字修飾約定。不同語言預設的呼叫呼叫約定和函式的命名方式是不同的,要想不同的語言開發的動態鏈結庫能夠相互呼叫,那麼開發動態鏈結庫的語言和呼叫鏈結庫的語言的函式約定必須...
C 呼叫約定和名字約定
c 呼叫約定和名字約定 呼叫約定 cdecl fastcall與 stdcall,三者都是呼叫約定 calling convention 它決定以下內容 1 函式引數的壓棧順序,2 由呼叫者還是被呼叫者把引數彈出棧,3 以及產生函式修飾名的方法。1 stdcall呼叫約定 函式的引數自右向左通過棧傳...
C 呼叫約定和名字約定
呼叫約定是指程式在函式呼叫時傳遞引數和獲取返回值所採用的方法 通過暫存器 或通過棧 或者是兩者的混合。用於指定calling convention的修飾符主要有 cdecl,stdcall,fastcall等。呼叫約定可以通過工程設定 setting.c c advanced callingconv...