http://linhs.blog.51cto.com/370259/140927
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++编译和链接时对函数名加工的细节问题,理解了这些细节后,如何运用完全就存乎一心了。
以上浅见,欢迎指正。
分享到:
相关推荐
C调用C++库,C调用C++库函数,简单实用。
利用c++不调用库函数分别实现数字图像的膨胀与腐蚀。可以掌握图像的膨胀腐蚀理论以及c++编程基础。。。。
这个例子演示了通过mcc将.m函数编译成动态链接库供c++调用的方式实现c++和matlab的交互。具体例子介绍请结合我的博文:blog.csdn.net/arackethis/article/details/43372553
c#调用c++库函数参数类型转换.docx
c++程序调用dll函数进行数据处理,并将dll处理后消息返回给c++程序
C++常用库函数示例,包括所有常用的库函数的使用例子,很适合初学者和需要使用库函数有难找到使用范例的使用者
C++矩阵库_C++调用矩阵_矩阵函数库_源码
VC环境下调用库函数的简单示例。以一个按钮为例。
详细介绍了使用VC++编写DLL lib 文件,以及对CVI调用的文件的过程,如有其他问题欢迎联系我。
不使用库函数strcpy(),编程实现将字符串b复制到字符串a中,不使用库函数strcpy(),编程实现将字符串b复制到字符串a中,不使用库函数strcpy(),编程实现将字符串b复制到字符串a中,不使用库函数strcpy(),编程实现将...
基于CSerial串口通信程序,供大家参考
PMAC库函数,关于C++如何调用动态链接库
支持查询C语言、C++库函数的调用方法,关键字的使用,以及库函数的函数返回值。
硬件平台为stm32f103,首先使用c++编译生成led驱动lib库文件,然后新建工程使用c++编译stm32主程序测试库函数的使用,编译debug调试正常。led驱动采用了类封装,大大提高代码可读性,同时也能保护关键隐私代码。软件...
C++标准库函数 c++程序通常可以调用标准c++库中的大量函数。这些函数完成一些基本的服务,如输入和输出等,同时也为一些经常使用的操作提供了高效的 实现代码。这些函数中含有大量的函数和类定义,以帮助程序员更好...
针对Tcl/Tk脚本中需要调用C/C++函数的问题,简要说明了Tcl/Tk命令的运行机理,给出了一个使用Tcl/Tk命令来调用C/C++动态链接库(DLL)函数的方案,并给出了将C/C++DLL函数封装为Tcl/Tk C库函数的解决方法.
C++调用Eigen库技巧的直观理解 包含常用的Eigen库函数及使用方法
之前在使用VC++6.0写逆向分析中注册机代码调试的时候调用了cin出现'streambuf': No such file or directory的问题。 原因在于库函数少了,下载这个文件将其放到 (你的安装目录)\VC98\INCLUDE,比如我自己的就是C:\...
C++ mfc 库函数 cdc 更好的查阅资源,包括画图形,和一些基本的使用方法等,绘图一般在视图类的(屏幕/打印机)绘图消息响应函数OnDraw中进行 每次需要重绘窗口时(程序启动/窗口大小改变/全部或部分窗口重现/程序员...
所有的 C / C++ 函数 Constructors (cppstring) Constructors (cppvector) Operators (cppbitset) Operators (cppdeque) Operators (cppstack) Operators (cppstring) Operators (cppvector) abort (stdother...