修饰名
C 和 C++ 程序中的函数、数据和对象均在内部由其修饰名表示。 “修饰名”是编译器在编译对象、数据或函数定义期间创建的编码字符串。 它记录名称以及调用约定、类型、函数参数和其他信息。 此名称修饰(也称为“名称重整”)可帮助链接器在链接可执行文件时查找正确的函数和对象。
修饰的命名约定在各种版本的 Visual Studio 中有所不同,并且可能在不同的目标体系结构上也不同。 若要正确链接使用 Visual Studio、C 和 C++ 创建的源文件,应使用相同的编译器工具集、标志和目标体系结构编译 DLL 和库。
注意
通过 Visual Studio 2022,Visual Studio 2015 或更高版本生成的库可由使用更高版本的 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
调用约定时进行修饰。
调用约定 | Decoration |
---|---|
__cdecl |
前导下划线 (_ ) |
__stdcall |
前导下划线 (_ ) 和尾随 at 符号 (@ ) 后接参数列表中以十进制为单位的字节数 |
__fastcall |
前导和尾随 at 符号 (@ ) 后接参数列表中表示字节数的十进制数字 |
__vectorcall |
两个尾随 at 符号 (@@ ) 后接参数列表中字节的十进制数字 |
对于具有 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)"