在C++中,由于重载等技术的存在,编译器要将函数、结构体、类等等的信息传递给链接器,就不能像C语言那样简单地通过函数名来完成,它需要提供额外的参数信息,而还要和C语言共用链接器,这就需要用到名字改编(name mangling),又叫名字修饰(name decoration)。
名字改编也罢,但由于历史原因,C++没有这方面的标准(C++没有ABI方面的标准,名字改编只是ABI问题的一部分)。于是编译器们各自为政,生成的文件无法通用。
于是:在Windows下,你会发现,同一版本的QtCore4.dll,不同编译器编译出来的无法通用。同一个函数void f(std::wstring s),同一个编译器(MSVC),不同选项(/Zc:wchar_t-或/Zc:wchar_t),导出的符号不同。
在Qt中,我们只关注下面两种名字改编:
注:对于Intel编译器,在Windows下和微软ABI一致,在其他平台下和GCC保持一致。
找个什么例子呢?额... 不妨找个简单的动态库,看看它导出的函数名字吧。Qt的Core和Gui模块都太复杂了,就拿Qt的Test模块来看看吧,QtTest4.dll 或 libQtTest.so.4.8.0
如何看到符号呢?
dumpbin /EXPORTS qttest4.dll
nm -D libQtTest.so.4.8.0
readelf -Ws libQtTest.so.4.8.0
准备工作完毕,你运行上述命令,即可看到大量的符号出现在屏幕上,我们下面对比Qt Manual给出的函数,看看这些符号(只简单看几个,不然我也看不懂)
| 
 放一行太长了,只好这样了,原型/Itanium/Microsoft  | 
||
| 
 1  | 
 void QTest::qSleep(int ms)  | 
 原型  | 
| 
 _ZN5QTest6qSleepEi  | 
 Itanium ABI  | 
|
| 
 ?qSleep@QTest@@YAXH@Z  | 
 Microsoft ABI  | 
|
| 
 2  | 
 const char * QTest::currentTestFunction()  | 
|
| 
 _ZN5QTest19currentTestFunctionEv  | 
||
| 
 ?currentTestFunction@QTest@@YAPBDXZ  | 
||
| 
 3  | 
 int QTest::qExec(QObject *testObject, int argc=0, char **argv=0)  | 
|
| 
 _ZN5QTest5qExecEP7QObjectiPPc  | 
||
| 
 ?qExec@QTest@@YAHPAVQObject@@HPAPAD@Z  | 
||
| 
 4  | 
 int QTest::qExec(QObject *testObject, const QStringList &arguments)  | 
|
| 
 _ZN5QTest5qExecEP7QObjectRK11QStringList  | 
||
| 
 ?qExec@QTest@@YAHPAVQObject@@ABVQStringList@@@Z  | 
||
| 
 5  | 
 QTestData & QTest::newRow(const char * dataTag)  | 
|
| 
 _ZN5QTest6newRowEPKc  | 
||
| 
 ?newRow@QTest@@YAAAVQTestData@@PBD@Z  | 
||
| 
 6  | 
 ...  | 
|
| 
 ...  | 
||
| 
 ...  | 
||
这堆东西,乱七八糟的,怎么看啊??
| 
 void QTest::qSleep(int ms)  | 
 原型  | 
| 
 _ZN5QTest6qSleepEi  | 
 Itanium ABI  | 
| 
 ?qSleep@QTest@@YAXH@Z  | 
 Microsoft ABI  | 
_ZN5QTest6qSleepEi
加几个空格
_Z N 5 QTest 6 qSleep E i
| 
 _Z  | 
 C++名字前缀  | 
|
| 
 N...E  | 
 复合名字起始字符 QTest::qSleep  | 
|
| 
 5 QTest  | 
 长度为5的名字QTest  | 
|
| 
 6 qSleep  | 
 长度为6的名字qSleep  | 
|
| 
 i  | 
 参数类型 int  | 
?qSleep@QTest@@YAXH@Z
这个信息有些多,有些乱,比前面的风格差远了。而且很多过时的东西都混在其中。
| 
 ?  | 
 C++名字前缀  | 
| 
 qSleep  | 
 最内层的名字  | 
| 
 @  | 
 名字分隔符  | 
| 
 QTest  | 
 前一个名字的外层名字  | 
| 
 @@  | 
 名字结束  | 
| 
 Y  | 
 函数调用是 near 方式  | 
| 
 A  | 
 调用惯例__cdecl  | 
| 
 X  | 
 返回值类型 void  | 
| 
 H  | 
 参数类型 int  | 
| 
 @  | 
 参数表结束  | 
| 
 Z  | 
 表示这是一个函数  | 
关于这些东西的解释,详见calling_conventions
http://stackoverflow.com/questions/4667266/c-name-mangling-by-hand
http://labs.qt.nokia.com/2009/08/12/some-thoughts-on-binary-compatibility/
http://developer.qt.nokia.com/wiki/toStdWStringAndBuiltInWchar_SimplifiedChinese
http://blog.csdn.net/dbzhang800/article/details/6707051
原文:http://www.cnblogs.com/findumars/p/5104247.html