作者:星轨(oRbIt)
E_Mail:inte2000@163.com
转载请注明原作者,否则请勿转载
函数名字修饰(Decorated Name)方式
函数的名字修饰(Decorated Name)就是编译器在编译期间创建的一个字符串,用来指明函数的定义或原型。LINK程序或其他工具有时需要指定函数的名字修饰来定位函数的正确位置。多数情况下程序员并不需要知道函数的名字修饰,LINK程序或其他工具会自动区分他们。当然,在某些情况下需要指定函数的名字修饰,例如在C++程序中,为了让LINK程序或其他工具能够匹配到正确的函数名字,就必须为重载函数和一些特殊的函数(如构造函数和析构函数)指定名字装饰。另一种需要指定函数的名字修饰的情况是在汇编程序中调用C或C++的函数。如果函数名字,调用约定,返回值类型或函数参数有任何改变,原来的名字修饰就不再有效,必须指定新的名字修饰。C和C++程序的函数在内部使用不同的名字修饰方式,下面将分别介绍这两种方式。
1. C编译器的函数名修饰规则
对于__stdcall调用约定,编译器和链接器会在输出函数名前加上一个下划线前缀,函数名后面加上一个“@”符号和其参数的字节数,例如_functionname@number。__cdecl调用约定仅在输出函数名前加上一个下划线前缀,例如_functionname。__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,例如@functionname@number。
2. C++编译器的函数名修饰规则
C++的函数名修饰规则有些复杂,但是信息更充分,通过分析修饰名不仅能够知道函数的调用方式,返回值类型,参数个数甚至参数类型。不管__cdecl,__fastcall还是__stdcall调用方式,函数修饰都是以一个“?”开始,后面紧跟函数的名字,再后面是参数表的开始标识和按照参数类型代号拼出的参数表。对于__stdcall方式,参数表的开始标识是“@@YG”,对于__cdecl方式则是“@@YA”,对于__fastcall方式则是“@@YI”。参数表的拼写代号如下所示:
X--void
D--char
E--unsigned char
F--short
H--int
I--unsigned int
J--long
K--unsigned long(DWORD)
M--float
N--double
_N--bool
U--struct
....
指针的方式有些特别,用PA表示指针,用PB表示const类型的指针。后面的代号表明指针类型,如果相同类型的指针连续出现,以“0”代替,一个“0”代表一次重复。U表示结构类型,通常后跟结构体的类型名,用“@@”表示结构类型名的结束。函数的返回值不作特殊处理,它的描述方式和函数参数一样,紧跟着参数表的开始标志,也就是说,函数参数表的第一项实际上是表示函数的返回值类型。参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。下面举两个例子,假如有以下函数声明:
int Function1(char *var1,unsigned long);
其函数修饰名为
“?Function1@@YGHPADK@Z”,而对于函数声明:
void Function2();
其函数修饰名则为
“?Function2@@YGXXZ” 。
对于C++的类成员函数(其调用方式是thiscall),函数的名字修饰与非成员的C++函数稍有不同,首先就是在函数名字和参数表之间插入以“@”字符引导的类名;其次是参数表的开始标识不同,公有(public)成员函数的标识是“@@QAE”,保护(protected)成员函数的标识是“@@IAE”,私有(private)成员函数的标识是“@@AAE”,如果函数声明使用了const关键字,则相应的标识应分别为“@@QBE”,“@@IBE”和“@@ABE”。如果参数类型是类实例的引用,则使用“AAV1”,对于const类型的引用,则使用“ABV1”。下面就以类CTest为例说明C++成员函数的名字修饰规则:
class CTest
{
......
private:
void Function(int);
protected:
void CopyInfo(const CTest &src);
public:
long DrawText(HDC hdc, long pos, const TCHAR* text, RGBQUAD color, BYTE bUnder, bool bSet);
long InsightClass(DWORD dwClass) const;
......
};
对于成员函数Function,其函数修饰名为“?Function@CTest@@AAEXH@Z”,字符串“@@AAE”表示这是一个私有函数。成员函数CopyInfo只有一个参数,是对类CTest的const引用参数,其函数修饰名为“?CopyInfo@CTest@@IAEXABV1@@Z”。DrawText是一个比较复杂的函数声明,不仅有字符串参数,还有结构体参数和HDC句柄参数,需要指出的是HDC实际上是一个HDC__结构类型的指针,这个参数的表示就是“PAUHDC__@@”,其完整的函数修饰名为“?DrawText@CTest@@QAEJPAUHDC__@@JPBDUtagRGBQUAD@@E_N@Z”。InsightClass是一个共有的const函数,它的成员函数标识是“@@QBE”,完整的修饰名就是“?InsightClass@CTest@@QBEJK@Z”。
无论是C函数名修饰方式还是C++函数名修饰方式均不改变输出函数名中的字符大小写,这和PASCAL调用约定不同,PASCAL约定输出的函数名无任何修饰且全部大写。
3.查看函数的名字修饰
有两种方式可以检查你的程序中的函数的名字修饰:使用编译输出列表或使用Dumpbin工具。使用/FAc,/FAs或/FAcs命令行参数可以让编译器输出函数或变量名字列表。使用dumpbin.exe /SYMBOLS命令也可以获得obj文件或lib文件中的函数或变量名字列表。此外,还可以使用 undname.exe 将修饰名转换为未修饰形式。
(未完)
分享到:
相关推荐
函数调用约定与函数名称修饰规则是编程中至关重要的概念,尤其在使用C/C++时。函数调用约定,也称为调用约定或调用约定协议,规定了函数调用时参数如何入栈、谁负责清理栈以及如何传递返回值。函数名修饰规则则涉及...
### 函数调用约定与函数名称修饰规则 #### 调用约定(Calling Convention) 调用约定是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变以及由谁...
C++函数调用约定是编程过程中非常重要的概念,它规定了函数调用时参数传递的顺序、谁负责清理堆栈以及函数名是否需要修饰。在Visual C/C++编译器中,有四种主要的函数调用约定:__cdecl、__stdcall、__fastcall和...
函数调用约定(Calling Convention)在程序设计中扮演着重要的角色,它决定了函数参数如何传递、栈的清理方式以及函数名称如何进行修饰等问题。不同的调用约定对程序性能、可移植性和兼容性等方面都有着直接影响。...
### DLL中调用约定与名称修饰详解 #### 一、调用约定(Calling Convention) 调用约定是在程序设计语言中为了实现函数调用而建立的一种协议。它规定了该语言的函数中的参数传递方式、参数是否可变以及由谁来处理...
在程序设计领域中,函数调用约定(Calling Convention)是定义如何传递参数、清理栈空间以及如何分配寄存器等的一组规则。这些规则对于确保程序正确运行至关重要,尤其是在涉及不同编译器或语言间的交互时。本文将...
在C++语言中,函数符号生成规则主要有四种:cdecl调用约定、std call调用约定、fastcall调用约定和thiscall调用约定。 1. cdecl调用约定:”?+函数名+参数类型代号+函数返回类型代号+参数类型代号+结束标识”...
在C和C++编程中,函数的调用约定(Calling ...总之,理解并正确使用函数调用约定和函数名修饰规则是避免C和C++程序中常见错误的关键。正确应用这些规则可以保证程序的正确链接和执行,提高代码的兼容性和可维护性。
函数调用约定是编程语言中规定函数调用过程的一个重要机制,主要涉及到参数传递和堆栈清理的责任分配。在C和C++中,不同的调用约定适用于不同的场景,特别是涉及到DLL(动态链接库)和Win API函数时,选择正确的调用...
总的来说,DLL的创建与函数调用规则涉及MFC的使用、DLL类型的选择以及入口函数的编写等多个方面,理解这些规则是开发高效、稳定的Windows应用程序的关键。开发者需要根据具体需求选择合适的DLL类型,并遵循相应的...
调用约定是编程语言中一个重要的概念,它决定了函数调用时参数如何传递以及栈如何管理。__stdcall、__cdecl和__fastcall各有优势和应用场景,选择合适的调用约定对于优化代码性能和提高程序的可维护性至关重要。了解...
在C/C++编程语言中,函数调用方式是程序设计中的关键概念之一,它涉及到如何在函数调用过程中处理参数的传递以及栈空间的管理。根据给定的文件信息,我们可以深入探讨C/C++中几种主要的函数调用方式:__cdecl、__...
4. 函数名修饰:`stdcall`函数也会进行名称修饰,但与`cdecl`不同,它的修饰规则是为了适应Windows API,一般不会包含参数类型信息,而是以`@`符号后跟参数总字节数表示。 在C#中,虽然没有直接使用`cdecl`或`...
与stdcall不同的是,函数调用结束后,由调用者负责清理堆栈,这使得C调用约定可以支持参数个数不固定的情况。这也反映了C语言的灵活特性。 3. fastcall调用约定:此调用约定旨在提高参数传递的效率。它将部分参数...
在stdcall约定下,函数调用会先压入第二个参数,然后是第一个参数,函数内部通过相对ebp的偏移量获取参数值,函数结束时自己清理栈。而在cdecl约定下,虽然参数压栈顺序相同,但清理栈的责任在于调用者。 了解这些...
#### 二、函数调用约定概述 函数调用约定主要涉及以下几个方面: - 参数传递的方式; - 函数返回值的处理; - 调用者与被调用者之间如何分配清理栈的责任; - 函数名称在链接过程中的变化。 #### 三、C++中常见的...
理解函数调用约定对于编写跨平台或与特定编译器交互的代码至关重要。不同的编译器可能有不同的默认调用约定,或者提供自定义约定的选项。例如,fastcall调用约定通常用于优化性能,通过寄存器传递部分参数,减少堆栈...
Windows调用约定是指Windows平台下函数调用时的规则和约定,它是编译器在生成函数调用代码时遵循的一套机制,以确保调用方与被调用方之间能够正确地传递参数和处理函数返回值。在C++和C语言中,这些调用约定对程序的...