首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

函数签字(function signature)与符号修饰(name decoration)【转】

2013-08-16 
函数签名(function signature)与符号修饰(name decoration)【转】函数签名修饰后名称(符号名)int func(int)_

函数签名(function signature)与符号修饰(name decoration)【转】

函数签名

修饰后名称(符号名)

int func(int)

_Z4funci

float func(float)

_Z4funcf

int C::func(int)

_ZN1C4funcEi

int C::C2::func(int)

_ZN1C2C24funcEi

int N::func(int)

_ZN1N4funcEi

int N::C::func(int)

_ZN1N1C4funcEi

?

GCC的基本C++名称修饰方法如下:所有的符号都以"_Z"开头,对于嵌套的名字(在名称空间或在类里面的),后面紧跟"N",然后是各个名称空 间和类的名字,每个名字前是名字字符串长度,再以"E"结尾。比如N::C::func经过名称修饰以后就是_ZN1N1C4funcE。对于一个函数来 说,它的参数列表紧跟在"E"后面,对于int类型来说,就是字母"i"。所以整个N::C::func(int)函数签名经过修饰为 _ZN1N1C4funcEi。更为具体的修饰方法我们在这里不详细介绍,有兴趣的读者可以参考GCC的名称修饰标准。幸好这种名称修饰方法我们平时程序 开发中也很少手工分析名称修饰问题,所以无须很详细地了解这个过程。binutils里面提供了一个叫"c++filt"的工具可以用来解析被修饰过的名 称,比如:

?

函数签名

修饰后名称

int func(int)

?func@@YAHH@Z

float func(float)

?func@@YAMM@Z

int C::func(int)

?func@C@@AAEHH@Z

int C::C2::func(int)

?func@C2@C@@AAEHH@Z

int N::func(int)

?func@N@@YAHH@Z

int N::C::func(int)

?func@C@N@@AAEHH@Z

?

我们以int N::C::func(int)这个函数签名来猜测Visual C++的名称修饰规则(当然,你只须大概了解这个修饰规则就可以了)。修饰后名字由"?"开头,接着是函数名由"@"符号结尾的函数名;后面跟着由"@" 结尾的类名"C"和名称空间"N",再一个"@"表示函数的名称空间结束;第一个"A"表示函数调用类型为"__cdecl"(函数调用类型我们将在第4 章详细介绍),接着是函数的参数类型及返回值,由"@"结束,最后由"Z"结尾。可以看到函数名、参数的类型和名称空间都被加入了修饰后名称,这样编译器 和链接器就可以区别同名但不同参数类型或名字空间的函数,而不会导致link的时候函数多重定义。

?

Visual C++的名称修饰规则并没有对外公开,当然,一般情况下我们也无须了解这套规则,但是有时候可能须要将一个修饰后名字转换成函数签名,比如在链接、调试程 序的时候可能会用到。Microsoft提供了一个UnDecorateSymbolName()的API,可以将修饰后名称转换成函数签名。下面这段代 码使用UnDecorateSymbolName()将修饰后名称转换成函数签名:

?

[cpp] view plaincopy
  1. /*?2-4.c?*?Compile:?cl?2-4.c?/link?Dbghelp.lib?
  2. *?Usage:?2-4.exe?DecroatedName?*/??
  3. #include?<Windows.h>??#include?<Dbghelp.h>??
  4. int?main(?int?argc,?char*?argv[]?)??{??
  5. char?buffer[256];??????if(argc?==?2)???
  6. {??UnDecorateSymbolName(?argv[1],?buffer,?256,?0?);??
  7. printf(?buffer?);??}???
  8. else???{??
  9. printf(?"Usage:?2-4.exe?DecroatedName\n"?);??}??
  10. ????return?0;??}??


由于不同的编译器采用不同的名字修饰方法,必然会导致由不同编译器编译产生的目标文件无法正常相互链接,这是导致不同编译器之间不能互操作的主要原因之一。我们后面的关于C++ ABI和COM的这一节将会详细讨论这个问题。

热点排行