C++调用C库函数详细讲解

C++调用C库函数详细讲解
2011年03月03日
  C++调用C库函数详细讲解
  文章录入:7747.Net 责任编辑:7747.Net 165
  【字体:小 大 】 C 调用C的库函数时,如果头文件定义得不恰当,可能会出现明明某函数在obj文件中存在,但是却发生链接失败的情况,出现如下错误:
  undefined reference to 'xxx'
  出现问题的原因是c库函数编译成obj文件时对函数符号的处理和C 不同。因为C 函数支持重载,所以函数符号的处理要更复杂一些,c往往不作修饰。
  例如有函数:
  /* dofunc.c */
  #include
  int dofunc()
  {
  printf("dofunc ");
  }
  使 用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库上去。
  常见有形如:
  __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 编译和链接时对函数名加工的细节问题,理解了这些细节后,如何运用完全就存乎一心了。
  #ifdef __cplusplus
  extern "C" {
  #endif
  int dofunc();
  #ifdef __cplusplus
  }
  #endif 的头文件声明。
  这种的头文件一般是库开发者提供的,能同时被c和c 模块使用。
  转自http://www.7747.net/kf/201009/74570.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值