5 解析未定义的符号(下)

来源:互联网 发布:e5 v3cpu 淘宝店推荐 编辑:程序博客网 时间:2024/05/16 10:08

——《软件调试实战》

C++的命名空间、类、模板或函数重载等特征使得编译和链接更为复杂,这使得符号的不匹配更有可能引发链接问题。甚至利用C和C++编译器编译相同的C源代码也会得到不同的符号。
nm

1 符号的反改编(demangle)
为观察经过名称改编的符号,可以对这些符号进行反改编。有两种反改编方法:一是使用实用程序(analysis utility),它们可以在改编和反改编之间切换;二是使用过滤器,如c++filt。通过选项-C或–demingle可以调用实际的用户级别的符号名称。
c++filt

2 连接C和C++代码
  仅使用C编译器驱动程序并不能保证源代码实际上被编译为C代码,编译器驱动程序可能根据文件扩展名来决定生成C或C++风格的符号。例如,如果用gcc编译 .c 文件,则此文件被编译为C代码,而扩展名为 .cc, .cpp, .cxx 的文件则被编译为C++代码。
  C++经常需要连接C对象文件中的符号,这往往导致链接上的问题。解决方法是明确地通知C++编译器不对哪些需要由C对象文件中的符号来解析的未定义符号进行名称改编。这可以通过在相应声明中使用extern "C" 编译器指令来实现。
  如下声明,可使函数factorail()被C++编译器编译后,仍可链接到C库中,避免链接时出现未定义符号。

//main.ccextern "C"{    unsigned factorial(unsigned n);}

3 识别编译器和连接器版本不匹配的问题
编译器不匹配的症状是:连接器报错(有符号丢失),但这些符号在对象文件或库中都存在。
  当试图链接不同的编译器(或版本)生成的对象文件时,就会发生对象的不匹配问题。最常见的情况是必须使用那些无法获得源代码的对象文件或库,例如第三方库。这种情况下,简单的修复方法不再有效,即无法使用相同的编译器和连接器重头开始构建。
  可以使用nm对两个对象文件的符号表进行分析:一是包含未解析符号的表,二是具有相应定义符号的表;将得出如下结果:已反改编的用户级别的符号是相同的,而经过名称改编的符号不同。
  下一步就是找出用于生出不同对象文件的编译器版本,并决定使用哪个编译器来编译和连接所有的对象文件和库。一种适用于几乎所有UNIX风格的平台的方法是在对象文件中搜索特定字符串,这些字符串给出了有关编译器版本的暗示。可用的方法是使用Unix工具(strings, grep)和编辑器(如emacs).如:
  String_GCC

4 ldd executablefie 打印库依赖关系,可知道还有那些库未找到。
ldd
  

0 0
原创粉丝点击