C++调用C的库函数 undefined reference to

转载 2012年03月23日 14:07:28
  C++调用C的库函数时,如果头文件定义得不恰当,可能会出现明明某函数在obj文件中存在,但是却发生链接失败的情况,出现如下错误:
  
  undefined reference to 'xxx'

  出现问题的原因是c库函数编译成obj文件时对函数符号的处理和C++不同。因为C++函数支持重载,所以函数符号的处理要更复杂一些,c往往不作修饰。

  例如有函数:

/* dofunc.c */

#include <stdio.h>
int dofunc()
{
        printf("dofunc\n");
}

  使用gcc编译成obj后
gcc -c dofunc.c
#生成 dofunc.o

objdump -x dofunc.o

[    0](sec -2)(fl 0x00)(ty     0)(scl 103) (nx 1) 0x00000000 dofunc.c
File
[    2](sec    1)(fl 0x00)(ty    20)(scl     2) (nx 1) 0x00000000 _dofunc
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[    4](sec    1)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .text
AUX scnlen 0x14 nreloc 2 nlnno 0
[    6](sec    2)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[    8](sec    3)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 10](sec    4)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x8 nreloc 0 nlnno 0
[ 12](sec    0)(fl 0x00)(ty    20)(scl     2) (nx 0) 0x00000000 _printf


  
  c的dofunc函数在obj文件里的符号为 _dofunc
  
  再看看使用g++编译后的代码:
 
g++ -c dofunc.c

objdump -x dofunc.o

SYMBOL TABLE:
[    0](sec -2)(fl 0x00)(ty     0)(scl 103) (nx 1) 0x00000000 dofunc.c
File
[    2](sec    1)(fl 0x00)(ty    20)(scl     2) (nx 1) 0x00000000 __Z6dofuncv
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[    4](sec    1)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .text
AUX scnlen 0x14 nreloc 2 nlnno 0
[    6](sec    2)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[    8](sec    3)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 10](sec    4)(fl 0x00)(ty     0)(scl     3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x8 nreloc 0 nlnno 0
[ 12](sec    0)(fl 0x00)(ty    20)(scl     2) (nx 0) 0x00000000 _printf

 g++编译后的函数符号名比较古怪:__Z6dofuncv

 
可见C和C++在加工函数名方面是很大不同的。

 
如果有C++程序要使用dofunc.o ,如下程序的函数声明是错的
 
// main_dev.cpp

int
 dofunc();

int main(int argc , char* args[])
{
    dofunc();
    system("pause");
}

g++  -o main_dev main_dev.cpp dofunc.o
main_dev.cpp: undefined reference to `dofunc()'
collect2: ld returned 1 exit status
  
  原因是dofunc函数在加工后函数名应该为__Z6dofuncv ,dofunc.o文件里面的是_dofunc,所以找不到。
  
  如果有dofunc的源代码,解决办法很简单,将dofunc.c使用c++来编译即可。
  如果不幸地dofunc函数在别人的库里面,而这个库是用c编写和gcc编译的,源代码不可见,那怎么办呢?
  幸亏C++和编译器的设计者早已料到了这个问题,并提供了一种通用的解决办法:使用extern "C"来修饰旧C库的外部函数声明。

   
extern "C" {
int dofunc();
}

int main(int argc , char* args[])
{
        dofunc();
        system("pause");
}

g++  -o main_dev main_dev.cpp dofunc.o
成功
  
  extern "C"修饰内的函数,一律按照c的风格来编译,以便能够链接到用c编译出来的obj库上去。
 
  常见有形如:

#ifdef __cplusplus
extern "C" {
#endif

int dofunc();


#ifdef __cplusplus
}
#endif

  的头文件声明。
  
  这种的头文件一般是库开发者提供的,能同时被c和c++模块使用。宏__cplusplus 是c++编译器定义的,这种写法保证了用C++编译时extern "C" 能生效;而用c编译时又不会因不会处理extern  "C"而错误。
  
  反过来,如果c需要调用C++编译的库又怎么办呢?相信一般情况下不会有这样奇特的要求,直接用C++编译不就完了?

  把main_dev.cpp改名为main.c ,然后
  
      gcc  -o main_dev main_dev.c dofunc.o
  
  当然会出现: undefined reference to `dofunc'
  
  因为fofunc.o里面的符号是
__Z6dofuncv  ,所以链接会失败,只能有一种非常恶心的方法去链到那个函数:

 
//main_dev.c

int (*dofunc)();    /* 声明函数指针   */

int _Z6dofuncv();  /* 会链接到   __Z6dofuncv   */


int main(int argc , char* args[])
{
    dofunc=_Z6dofuncv;  /* 函数指针赋值 */
    dofunc();
    system("pause");
}

gcc  -o main_dev main_dev.c dofunc.o
成功
  
  
   上面讲了那么多,中心意思都是c和c++编译和链接时对函数名加工的细节问题,理解了这些细节后,如何运用完全就存乎一心了。

    以上浅见,欢迎指正

本文出自 “软件工匠笔记” 博客,请务必保留此出处http://linhs.blog.51cto.com/370259/140927


C++代码调用C库中的 undefined reference解决办法

最近碰到两次在C++代码中调用别人写的C库代码出错问题,每次都报 undefined reference xxx函数。产看头文件包含了需要的.h文件,makefile中也添加了.h文件的路径和相应库的...
  • qgylygqi
  • qgylygqi
  • 2016年03月09日 14:12
  • 428

C++调用C函数

前言:以前见到extern "C"这样的语句,只是简单地知道跟外部链接有关,但是没有深刻理解它的意思。 首先,为什么要使用extern "C"修饰符? C++调用其它语言的函数,由于编译器生成...
  • Imcainiao11
  • Imcainiao11
  • 2012年03月19日 16:17
  • 28141

HP小型机故障诊断

  • zgqtxwd
  • zgqtxwd
  • 2008年04月26日 19:56
  • 151

php调用C代码的方法详解

在php程序中需要用到C代码,应该是下面两种情况:1 已有C代码,在php程序中想直接用2 由于php的性能问题,需要用C来实现部分功能针对第一种情况,最合适的方法是用system调用,把现有C代码写...
  • oyd
  • oyd
  • 2008年10月28日 17:10
  • 25857

C++程序调用C函数

这种需求很多,又因为C++和C是两种完全不同的编译链接处理方式,所以要稍加处理.总结大致有两大类实现方法.文中给出的是完整的,具体的,但又最基本最简单的实现,至于理论性的东西在网上很容易搜索的到. 一...
  • ustcgy
  • ustcgy
  • 2009年12月23日 15:41
  • 9230

如何在C++中调用C程序?

C++和C是两种完全不同的编译链接处理方式,如果直接在C++里面调用C函数,会找不到函数体,报链接错误。要解决这个问题,就要在 C++文件里面显示声明一下哪些函数是C写的,要用C的方式来处理。 1....
  • juanjuan888
  • juanjuan888
  • 2011年11月04日 11:46
  • 22415

关于Matlab调用C函数的问题

在进行算法验证的时候,Matlab无疑是一把利器,如果将用C写的代码,在用Matlab实现一遍,确实很浪费时间。当对于Matlab不是特别熟悉的时候,尤其麻烦。 关于Matlab调用C的方式,已经固...
  • tietao
  • tietao
  • 2013年06月20日 19:07
  • 2237

底层理解c语言

要想深入理解C语言就不得不要知道几个知识点: 1.众所周知用任意一高级语言(不是脚本语言)写的代码都要经过类似:预处理->编译成汇编代码(compilation)->汇编(assembly)->...
  • HyNeverGiveUp
  • HyNeverGiveUp
  • 2016年11月20日 22:15
  • 1922

C++调用C函数,为什么要加extern "C"?

C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(...
  • u011046042
  • u011046042
  • 2015年10月24日 08:24
  • 3352

C中调用C++与C++调用C

转自:http://www.cppblog.com/franksunny/archive/2007/11/29/37510.html 首先,在C中调用C++: 将 C++ 函数声明为``exter...
  • Devil_2009
  • Devil_2009
  • 2011年08月31日 10:00
  • 9469
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++调用C的库函数 undefined reference to
举报原因:
原因补充:

(最多只允许输入30个字)