裝飾名稱
C 和 C++ 程式中的函式、資料和物件在內部以其裝飾名稱表示。 裝飾名稱是編譯對象、數據或函式定義期間,編譯程式所建立的編碼字串。 它會記錄呼叫慣例、類型、函式參數和其他資訊,並連同名稱一起記錄。 這個名稱裝飾也稱為 名稱整改,可協助連結器在連結可執行檔時尋找正確的函式和物件。
裝飾的命名慣例已在各種 Visual Studio 版本中變更,而且在不同的目標架構上也可以不同。 若要正確連結使用 Visual Studio 所建立的來源檔案,C 和 C++ DLL 和連結庫應該使用相同的編譯程式工具組、旗標和目標架構進行編譯。
注意
Visual Studio 2015 或更新版本所建置的連結庫,可透過Visual Studio 2022 透過Visual Studio 2022使用以較新版本Visual Studio 建置的應用程式使用。 如需詳細資訊,請參閱 visual Studio版本之間的C++二進位相容性。
使用裝飾名稱
通常,您在撰寫程式碼時不必知道裝飾名稱,也能成功編譯和連結。 裝飾名稱是編譯器和連結器內部的實作詳細資料。 這些工具通常能夠處理未裝飾的名稱。 不過,當您指定函式名稱給連結器和其他工具時,有時需要裝飾名稱。 比方說,若要符合多載 C++ 函式、命名空間的成員、類別建構函式、解構函式和特殊成員函式,您必須指定裝飾名稱。 如需選項旗標和其他需要裝飾名稱之情況的詳細資訊,請參閱您使用之工具和選項的檔。
如果您變更函式名稱、類別、呼叫慣例、傳回型別或任何參數,裝飾名稱也會變更。 在此情況下,您必須取得新的裝飾名稱,並在指定裝飾名稱的每個地方使用。
在連結至以其他程式設計語言撰寫的程式碼或使用其他編譯器時,名稱裝飾也很重要。 不同編譯器會使用不同的名稱裝飾慣例。 當您的執行檔連結至以另一種語言撰寫的程式碼時,必須特別注意符合匯出和匯入的名稱和呼叫慣例。 元件語言程式代碼必須使用 MSVC 裝飾的名稱和呼叫慣例,連結至使用 MSVC 撰寫的原始程式碼。
C++裝飾名稱的格式
C++ 函式的裝飾名稱包含下列資訊:
函式名稱。
如果函式是成員函式,則為的類別。 裝飾可能包含包含函式之類別的類別等等。
如果函式是命名空間的一部分,則函式所屬的命名空間。
函式參數的類型。
呼叫慣例。
函式的傳回型別。
選擇性的目標特定專案。 在 ARM64EC 物件中,標記
$$h
會插入名稱中。
函式和類別名稱是以裝飾名稱編碼。 裝飾名稱的其餘部分是只在編譯器和連結器內部才有意的代碼。 以下是 C++ 未裝飾和裝飾名稱的範例。
未裝飾名稱 | 裝飾名稱 |
---|---|
int a(char){int i=3;return i;}; |
?a@@YAHD@Z |
void __stdcall b::c(float){}; |
?c@b@@AAGXM@Z |
C 裝飾名稱的格式
C 函式的裝飾形式取決於它的宣告中所使用的呼叫慣例,如下表所示。 這也是宣告C++程式代碼具有 extern "C"
連結時所使用的裝飾格式。 預設呼叫慣例是 __cdecl
。 在 64 位的環境中,C 或 extern "C"
函式只有在使用 __vectorcall
呼叫慣例時才會裝飾。
呼叫慣例 | 裝飾 |
---|---|
__cdecl |
前置底線 (_ ) |
__stdcall |
前置底線 (_ ) 和尾端符號 (@ ) 後面接著十進位參數清單中的位元元組數目 |
__fastcall |
符號的前置和尾端 (@ ) 後面接著十進位數,代表參數清單中的位元元組數目 |
__vectorcall |
兩個尾端符號 (@@ ) 後面接著參數清單中的十進位位元組數 |
對於具有 C 連結的ARM64EC函式(無論是編譯為 C 還是使用 extern "C"
),前面 #
會加上裝飾名稱。
檢視裝飾名稱
在編譯包含資料、物件或函式定義或原型的原始程式檔之後,您可以取得裝飾形式的符號名稱。 若要檢查您程式中的裝飾名稱,您可以使用下列任何一個方法:
使用清單檢視裝飾名稱
藉由編譯包含數據、物件或函式定義或原型的來源檔案來產生清單,並將
/FA
[列出檔類型] 編譯程式選項設定為具有原始程式碼的元件 (/FAs
)。例如,在開發人員命令提示字元中輸入
cl /c /FAs example.cpp
,以產生清單檔案example.asm
。在產生的清單檔案中,尋找開頭
PUBLIC
為 和 結尾的分號 (;
) 的行,後面接著未編碼的數據或函式名稱。 和分號之間的PUBLIC
符號是裝飾名稱。
使用 DUMPBIN 檢視裝飾名稱
若要檢視 OBJ 或 LIB 檔案中匯出的符號,請在開發人員命令提示字元中輸入
dumpbin /exports <obj-or-lib-file>
。若要尋找裝飾形式的符號,請尋找括號中的未裝飾名稱。 裝飾名稱位於同一行,在未編碼的名稱之前。
檢視未編碼的名稱
您可以使用 undname.exe 將裝飾名稱轉換成未裝飾形式。 此範例示範它的運作方式:
C:\>undname ?func1@a@@AAEXH@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.
Undecoration of :- "?func1@a@@AAEXH@Z"
is :- "private: void __thiscall a::func1(int)"