`
dawning126
  • 浏览: 46255 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用C++调用C的库函数

    博客分类:
  • C++
  • C
 
阅读更多


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的ABI,以及在C++侧处理C语言无法理解的特性。在实际应用中,需要注意兼容性、内存管理和错误处理等方面的问题,以确保代码的稳定性和可靠性。

    Linux下用c++调用自己的matlab函数的一个入门实例

    这个例子演示了通过mcc将.m函数编译成动态链接库供c++调用的方式实现c++和matlab的交互。具体例子介绍请结合我的博文:blog.csdn.net/arackethis/article/details/43372553

    C语言库函数 C语言库函数

    C语言库函数的使用方法通常是先包含相应的头文件,然后调用其中的函数。例如,要使用printf()打印字符串,需要这样编写代码: ```c #include int main() { printf("Hello, World!\n"); return 0; } ``` 在实际...

    c++不调用库函数实现图像的膨胀与腐蚀

    在C++中实现这些操作而不依赖于库函数,可以帮助我们更深入地理解其内部机制。本篇文章将详细讲解如何用C++实现图像的膨胀和腐蚀,并探讨相关理论和编程基础。 首先,我们要了解膨胀和腐蚀的基本概念。膨胀操作是将...

    Microsoft C C++ 和VC++ 库函数用法详解

    在Microsoft的开发环境中,C和C++语言是广泛使用的编程工具,尤其是与Visual C++(简称VC++)结合时,可以构建高效、可扩展的应用程序。VC++集成了C和C++编译器,以及一系列的库函数,帮助开发者实现各种功能。本篇...

    C语言库函数源代码分析

    《C语言库函数源代码分析》是一本专为C++程序员设计的参考资料,它深入剖析了C语言库函数的源代码,为读者提供了对底层编程和嵌入式编程的深刻理解。这本书分为上下两册,即《Turbo C++运行库函数源程序与参考大全》...

    C语言库函数示例教程 C语言库函数示例教程

    C语言库函数是C编程中的重要组成部分,它们提供了一系列预定义的功能,可以帮助程序员高效地完成各种任务。本教程旨在深入探讨C语言库函数,并通过实例来解析其用法。 1. **标准输入输出函数** - `printf()`:用于...

    c#调用c++库函数参数类型转换.docx

    C# 调用 C++ 库函数参数类型转换 在本文中,我们将探讨 C# 调用 C++ 库函数参数类型转换的问题。首先,我们需要了解 C# 和 C++ 之间的数据类型转换问题,以及指针或地址参数传送的问题。 数据类型转换问题 由于 ...

    c++调用dll,实现消息回调

    首先,我们需要理解C++调用DLL的基本步骤: 1. 创建DLL:在DLL项目中,定义一个函数,例如处理数据的函数`ProcessData`。这个函数可能接收一些参数,完成特定的计算或处理,然后返回结果。同时,为了实现回调,我们...

    纯C语言 库函数 chm

    本资源是专门为学习和使用纯C语言库函数设计的,包含两个CHM(Compiled Help Manual)格式的帮助文档——"C函数查询.chm"和"C语言库函数速查手册.chm",旨在帮助开发者深入理解和快速查询C语言中的库函数。...

    LabVIEW调用库函数节点.rar

    调用库函数节点是LabVIEW中的一个重要组件,它使得工程师和科学家可以利用已有的C/C++代码库,而不必重新编写整个程序。这大大提高了开发效率,尤其是在处理复杂计算、硬件接口或者需要利用第三方库时。 **一、调用...

    C++常用库函数示例

    在C++编程中,库函数是预编译的代码片段,提供了一系列的接口,供开发者调用以实现特定功能。这些库极大地扩展了C++语言的基础能力,使得开发者能够更高效地编写程序。本资源“C++常用库函数示例”集合了多个章节,...

    C语言库函数使用实例

    本文将深入探讨C语言库函数的使用,按照函数名的首字母进行分类,帮助你理解和掌握这些重要工具。 1. **数学运算(Math)** - `abs()`:计算整数的绝对值。 - `ceil()`:向上取整,返回大于或等于给定浮点数的...

    Visual C++经典(库函数)——库函数一网打尽!!!

    7. **C Run-Time (CRT)库**:这是C语言的基础库,包括内存管理、输入/输出、字符串处理等功能,Visual C++也支持这部分库。 掌握Visual C++的库函数是成为熟练开发者的关键步骤。理解并能灵活运用这些库,不仅可以...

    C语言常用库函数使用要点

    此外,需要注意的是C语言区分大小写,因此在调用库函数时,应使用正确的大小写形式。 2. **函数名的选择**:不同的编译系统可能会有不同的库函数集合,因此在使用某个特定编译器时,应当查阅相应的文档来确认可用的...

    c语言库函数大(所有字母开头的)

    在C语言中,库函数是预编译的代码集合,为程序员提供了许多便捷的功能,以完成常见的任务。这里我们讨论一些以A、W开头的C语言库函数。 首先,我们来看`abort()`函数,它是标准C库中的一个函数,位于`stdlib.h`...

    c++库函数(包括c)

    在编程世界中,C++和C语言是两个非常重要的编程语言,它们的库函数是学习和使用过程中的关键部分。库函数是预先编译好的函数集合,开发者可以通过调用这些函数来实现各种复杂的操作,无需从零开始编写代码。本资源...

    C++Reference(库函数)

    "C++ Reference" 是一个针对C++库函数的重要参考资料,主要提供英文版本的详细文档,帮助开发者理解和使用C++标准库中的各种功能。这个压缩包包含了一个名为"C++ Reference.chm"的文件,这通常是一个Windows平台上的...

    库函数调用示例.7z

    在Windows环境下,Visual C++(简称VC)是一种广泛使用的C/C++集成开发环境,它允许程序员创建各种应用程序,包括与用户界面交互的GUI程序。在这个"库函数调用示例.7z"压缩包中,我们可能包含了一个简单的VC项目,...

    TC3.0C语言库函数搜索软件

    TC3.0是Turbo C++ 3.0的简称,它是一款经典的C++集成...总的来说,TC3.0C语言库函数搜索软件是为了解决C语言编程中查找库函数的问题,提高开发效率,它的存在对于使用TC3.0进行C语言编程的开发者来说是非常有价值的。

Global site tag (gtag.js) - Google Analytics