名称的特殊处理(Name Mangling)

先说一个事情, mangle 的意思是 vt.乱砍, 损坏; n. 碾压机。 这意味着 name mangling 就是要先把你精心想出的名字们碾碎, 再拼成独一无二的样子, 当然这么残忍的事情都是编译器瞒着你做的。
一般而言, member 的名称前会被加上 class 名称, 形成独一无二的命名, 例如:

class Bar(){public: int ival;};
//其中的 ival 可能变成这样:
//member 经过 name-mangling 后的结果之一
ival__3Bar

编译器你为何要这样? 请考虑这样的派生操作:

class Foo: public Bar{public: int ival;};
//所以必须 name-mangling 为:
class Foo
{
public:
    int ival__3Bar;
    int ival__3Foo;
};

而对于函数, 因为 member function 可以被重载化, 所以需要更广泛的 magling 手法(更残酷的碾碎, 嗯嗯), 如:

class Point
{
public:
    void (float newX);
    float x();
    ...
};
//转化为
class Point
{
public:
    //这样能行?
    void x__5Point(float newX);
    float x__5Point();
    ...
};

函数如果这么转化, 会导致被重载化的函数实体拥有相同的名称, 为了让它们独一无二, 唯有再加上它们的参数链表(可以从参数原型得到)。 如果把参数类型也编码进去, 就一定可以制造出独一无二的效果, 使我们的 x() 函数有良好的转换(但如果你声明 extern "C" , 就会压抑 nonmember functions的 mangling 效果):

class Point
{
public:
    void x__5PointFf(float newX);
    float x__5PointFv();
    ...
};

以上所示的只是 cfront 的编码方法, 目前的编译器并没有统一的编码方法。
把参数和函数名称编码在一起, 编译器于是在不同的编译模块之间达成了一种有限的类型检验。 如:


void print(const Point3d&){}


但意外的被这样声明和调用:


void print(const Point3d&);


两个实体如果拥有独一无二的 name-mangling, 那么任何不不正确的调用操作在链接时期就因无法决议而失败。有时候我们把它称为 “确保类型安全的链接行为”。 我觉得这样很乐观, 因为它只可以捕捉函数的标记(或叫做函数签名, 就是指 函数名称 + 参数数目 + 参数类型)错误: 如果 “返回类型” 声明错误, 就没办法检查出来!
在当前的编译系统中, 有一种所谓的 demangling 工具, 用来拦截名称并将其转换回去, 使用者仍然可以处于 “不知道类型名字的极大幸福之中”。
因为 name-mangling 的手法残忍, 结果不堪, 所以一般不会给使用者看到。

posted @ 2014-11-22 20:27  wu_overflow  阅读(931)  评论(0编辑  收藏  举报