C++函数名称修饰规律例解【之一】【原创qduwg】

来源:互联网 发布:淘宝售假扣24分影响 编辑:程序博客网 时间:2024/06/11 00:28

C++函数名修饰编码规则
-------------------------------
2010年8月19日qduwg原创

下面是总结的对C++名字修饰的一些规则,通过大量的实验搞出的。其中需要在VC内写一个小程序,然后通过单步调试,可以看出其编码规则,也

可以使用cl /Fc /c xx.cpp方法编译你的cpp文件,得到一个xx.COD文件,在那里也可以看到修饰后的名字及汇编代码等。当然不了解一点编码

规则,是无法看懂那些类似火星人编码的文字的。故废寝忘食一个多星期,白天晚上的干,才整理出来以下资料,也是自己心血的结晶。聊以抛

砖引玉。


com(int,int)
( 复数类构造函数

构造函数为?0,跟作用域comp,结束标志@@,函数访问类型Q,一般函数A常函数用B,调用规则E(this)。参数为2个整数,HH表示。@Z为函数标志

com com();
复数类构造函数,无参数。

构造函数为?0,跟作用域comp,结束标志@@,函数访问类型Q,一般函数A常函数用B,调用规则E(this)。无参数用X表示。Z为函数标志,前面没有那

个@号。

c1.add(c2); //c1,c2分别为复数类对象
)复数类成员函数。
?成员函数名add,域名comp,结束标志@@,QAE含义同前,返回值类型AAV1,引用本层类的对象,@分隔符,然后参数AAV1,也是引用本类对象,分

隔符@,函数结束标志@Z。注意此时最后面的@@Z的两个@之间没有数字的。(see below,后面情况有变化)

增加一层名字空间时:
         // 如果自定义了名字空间wang,可以看出作用域的变化。

增加二层名字空间时:
函数原型comp& add(comp& a)
// 如果在自定义名字空间wang外层又定义了一个gang名字空间域,可以看出作用域的变化。

增加二层名字空间时:
函数原型comp& add(comp& a,comp& b)        //函数参数为多个,且有重复前面的参数的时候。
//如果增加了多层名字空间,那么在参数的后面就会出现相应的层号1,2,3等,而且在原来的@@Z

的两个@之间增加一个数字0.表示重复前面第0号参数。 如果有不同类型参数,则填入相应代号即可,替换掉数字。参见后面实例描述。

cout<<i;

输出整数变量i,函数?6表示<<符号,后跟所在范围是@@,其中表示类型名

及包含的参数,DU分别表示字符类型char和类类型class,后面@@,为第二个参数类类型的具体描述,其中@为参数类型,

std@@为char_traits类所在域,然后是外层类$basic_ostream的范围std@@,然后是QAE,含义同前,接着是返回值类型,AAV是表示对一个对象的

引用,0和1分别表示所引用对象参数,0表示跟前面第0个相同,即@DU,1表示跟前面第1个相同即@D(注意序号从0开始算起)。然后是函数参数,

这里是H表示输出整数,最后是结束标志@Z。
注:这里的范围不是名字空间,是指有不同类构成的函数签名,跟前面的名字空间不同的。类模板名由$开头,然后是模板参数。

cout<<'\n';
//调用的内联函数
这个名字是没有类名修饰的名字,属于公有函数。开始是名字?6std@@,然后是YA,公有函数,调用约定A,返回值类型AAV表示对类引用(AA表示

引用,V表示类),后面是引用的类,由@@描述,其后紧跟的是参数表,其中@0是内联函数标志,@AAV10

表示与0号参数相同类型,@D表示字符类型参数,@Z表示函数。

char * p,cout<<*p;
//调用的内联函数
const char * p,cout<<*p;
//调用的内联函数

const unsigned char ch='a';const unsigned char * p=&ch;cout<<*p;
//@E是unsigned char

cout<<ch
//调用的内联函数

cout<<f
      //调用的成员函数

cout<<db
      //调用的成员函数

cout<<ld
      //调用的成员函数

cout<<s
      //调用的成员函数

-------------------------------------------

在外层名字空间wang内定义了Time类,然后作为参数传递给comp& add(comp&,Time&),返回comp&

QAE后的AAV1表示返回本类类型数据,第二个@AAV123表示参数类型也是对本类型的引用,@AAVTime@3对第三层名字空间内的Time进行引用作为参

数。
层次关系可以看出从左往右排列,名字空间是从内层往外层的顺序。@3表示域代号,在第三层。从内往外数。

inline comp& add(comp& a,Time& b)内联函数

comp& add(comp& a,Time& b) 普通类外函数处于第二层名字空间

上面这两个函数不管是不是inline都一样的名字。编译后代码相同。但是名字跟前面的不同,因为不属于某个类的函数了。AAVcomp表示返回值类

型,@12表示在层号序列。@AAV312表示引用类型跟前面位于12层的相同。@AAVTime@2表示参数类型是对位于第二层上的Time的引用。所有层号都

是站在本函数的角度向外看出去时确定的层号。

------------------------------------------
在comp类内声明内联函数
inline comp& add(comp& a,Time& b),可以看到跟前面情况一样的。也不属于类成员。

函数定义为三个参数时
inline comp& add(comp& a,Time& b,comp& c)

函数定义为三个参数时
inline comp& add(Time& b,comp& a,comp& c)

函数定义为三个相同的参数时
inline comp& add(comp& d,comp& a,comp& c)

注释:可以看出,在非成员函数内,AAV3开头的都是跟函数返回值类型有关的引用。
------------------------------------------

函数定义为三个参数时且为comp类的成员:
class comp& comp::add(comp& a,Time& b,comp& c)

class comp& comp::add(Time& b, comp& a,comp& c)

comp& add(comp& a,comp& c,Time& b);

作为类成员函数的时候,参数表里面参数的位置改变,编码后的名字顺序也改变。但是如果有重复的参数,后面参数只写序号,而且是相对参数

表来说的,参数表第一个参数的序号为0.
注释:可以看出,在成员函数内,AAV1开头的都是跟函数返回值类型有关的引用,而且都是本类类型的引用。
---------------------------------------
返回值为Time类型时:
class Time& comp::add(comp& a,Time& b,comp& c);
//@AAV43中的@AAV4参考前面的3层上的类型。
返回值为Time类型时:
class Time& comp::add(comp& a,comp& c,Time& b)
                ***
返回值为Time类型时:
class Time& comp::add(Time& b, comp& a,comp& c)

返回值为Time类型时:
class Time& comp::add( comp& a,Time& b,comp& c,Time& d)

注释:可以看出,在成员函数内,AAV4开头的都是跟函数返回值类型有关的引用。后面所跟数字即返回值类型所在层次路径数字。
返回类型跟当前类不一致。
---------------------------------------------
返回值为student类型时:参数为4个。class student放在所有自定义名字空间之外。
class student& comp::add( comp& a,student& b,comp& c,student& d)


QAEAAVstudent@@最后的两个@@之间没有数字,说明前面那个返回值类型是全局类。

返回值为student类型时:参数为4个。放在gang名字空间内
            ***

返回值为student类型时:参数为4个。放在wang名字空间内。

注释:可以看出,在成员函数内,AAV4开头的都是跟函数返回值类型有关的引用。后面所跟数字即返回值类型所在层次路径数字。
返回类型跟当前类不一致。

---------------------------------
student类放在wang名字空间,跟comp平行时:add函数不是类成员。放在类外了。
class student& add( comp& a,student& b,comp& c, student& d)
@AAVcomp@12 @AAV312 @01@Z         ***
student类放在wang名字空间,跟comp平行时:add函数不是类成员。放在类外了。五个参数,
class student& add( comp& a,student& b,comp& c, student& d,Time& t)

返回值是comp&类型:
class comp& add( comp& a,student& b,comp& c, student& d,Time& t)

返回值是Time&类型:

注释:可以看出,在非成员函数内,AAV3开头的都是跟函数返回值类型有关的引用。

-----------------------------------------------

返回值为student类型时:参数为4个。把student类放在comp类内,初始化时加上前缀域名,否则找不到。函数放在comp类外。
class comp::student& add( comp& a,comp::student& b,comp& c,comp::student& d)
@AAV412 @AAV3412 @01@Z //不是类成员函数了,前面没有类名comp了。返回值类型带。

@AAV412:412代表了comp,@AAV3412,表示参数类型student在comp内。

把student类放在time类内,作为Public。引用student时必须写上前缀Time:: 函数Add写在comp类外的wang名字空间。
class Time& add( comp& a,Time::student& b,comp& c, Time::student& d,Time& t)


把student类放在time类内,作为Public。返回值为student类型时

在time类外又加了一层名字空间hongxia后,student类放在Time类内。
class hongxia::Time::student& add( comp& a,hongxia::Time::student& b,comp& c, hongxia::Time::student& d,hongxia::Time& t)

规律:总是以函数作为起点向外看出去时,遇到的层数即名字空间嵌套层数为1,2....,最外层号数最大,比如上述例子都是2,即gang名字空间

的代号。然后凡是返回值类型都从3编号,其所在类型号码为从内向外增加,比如student作为返回值类型,则其代号为3,所在外层类型依次加1

,如time类型为4,然后如果外面还有一个层,则为5,依次类推,然后是最外层号2.所有AAV的构成规律得到解决。

下面是又在最外层加了一层dong名字空间后的调用结果:

看出从add函数往外看出到最大层数是3,因此必然返回参数的编号从4开始。从返回类型层往外数到add函数的外一层,比如这里是2,所以是Time

层数是5,外面的hongxia是6,然后是2层和3层。所以可以看出编码规律AAV5623肯定是Time所在位置。而AAV45623一定是返回参数类型所在位置

了。这里的4表示就是最大层数3以后的序号,一定从最大层数下一个开始作为返回参数类型。然后后面就是所在类型的编号。

前面的域名后面的23表示从比add函数高一层的那个空间开始编号。也即2是add所在空间函数返回类型所在空间的共同的空间。说白了

就是要从共同所在层的层号开始写出层序列。

=================================================================
上面这些规律是费了一周的时间,废寝忘食通宵达旦的调试程序,查找资料,MSDN,网上的有关参考资料等,才整理出来的规律。希望对那些对

内部名字修饰(Name Mangling 或者Name Decoration)的朋友做一参考,也是抛砖引玉。毕竟这个问题也困扰了我好久好久。终于有一个名目了。

也是这一周多的时间的心血的结晶吧。

ps:参考小程序在另外一个页面。

原创粉丝点击