C++(Name Mangling)的详细说明
在70年代以前,Compiler产生Object档时,符号名称和对应的变量、函数名称是一样的,也就是说如果你在code声明定义一个foo函数,foo在Object档中对应的符号名称也叫做foo。
这样的设计有个缺点,如果你使用C Library,你就不能使用C Library已经定义好的变量与函数名称,否则有重复定义的问题
因此后来UNIX就规定code经过编译之后,要在对应的符号名称前加入"_",比如说"foo"就变成"_foo"
这个方法的确可以减少符号冲突的机率,但是并没办法完全解决符号冲突的问题,因此C++加入了Namespace来解决符号冲突的问题
C++有继承和多载等特性,以多载来说,要让Compiler能分辨两个相同名称的函数,就必须要在产生的符号上动一些手脚,这个动作叫做Name Mangling
以下列这个例子来说
- int func(int);
- float func(float);
- class C {
- int func(int);
- class C2 {
- int func(int);
- };
- };
- namespace N {
- int func(int);
- class C {
- int func(int);
- };
- }
这段代码一共有6个func函数,他们不同的地方只有参数以及Namespace不一样,Compiler会使用这些函数的Function Signature来辨别他们
Function Signature会加入函数所在Class以及Namespace等信息,用来辨别不同的函数,就好像函数的签名一样
例如:
- class C { Function Signature
- int func(int); ==> int C::func(int)
- class C2 {
- int func(int); ==> int C::C2::func(int)
- };
- };
- namespace N {
- int func(int); ==> int N::func(int)
- class C {
- int func(int); ==> int N::C::func(int)
- };
- }
当compiler在把source code编译成object档的时候,会使用Name Mangling这个方法,把Function Signature修饰后转成对应的符号,例如(使用GCC):
修饰过后的符号名称:
int C::C2::func(int) ==> _ZN1C2C24funcEi
int N::C::func(int) ==> _ZN1N1C4funcEi
int func(int) ==> _Z4funci
float func(float) ==> _Z4funcf
GCC的C++名称修饰规则如下
1.所有的符号都由"_Z"开头
2.如果是巢状的名称,就在开头的"_Z"之后加上"N"
3.接下来是Namespace以及Class的名称,写法为字符串长度 + "N" or "C"
4.如果是巢状名称的话,最后以"E"结尾
5.E后面接retrun type,int写为i,float写为f
此外binutils当中提供一个工具"c++filt"可以帮我们解析修饰过得名称
- ex:
- $ c++filt _ZN1N1C4funcEi
- N::C::func(int)
C++的global varible以及static varible同样也会经过修饰,例如Namespace foo中的global varible bar会被修饰成 _ZN3foo3barE
不同编译器Name Mangling的作法通常会不一样,例如Visual C++就使用和GCC完全不同的Name Mangling方法
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
