C和C++互相调用动态库

c++ c++ 2102 人阅读 | 0 人回复

发表于 2023-2-23 10:50:48 | 显示全部楼层 |阅读模式

平时需要接触c和c++,有时会遇到两种语言互相调用动态库的情况,这时就要对代码进行一些处理,做个记录。

前提
两种语言生成的库是无法直接互相调用的,原因在于c++支持重载,因此存在改名机制(也可能是因为有改名机制所以支持重载 ==!)_,即生成的中间文件会对函数名进行改写,会将函数名与参数列表相结合生产新的函数名,这样就可以通过不同的函数名来区分重载函数了。
而C语言没有改名机制,函数名未改动,若两种语言直接调用,便会报错:函数名未定义。
eg:
C++代码 ,cplus.cpp 和 cplus.h

  1. #include<stdio.h>
  2. int sayCplus()
  3. {
  4.     printf("Hello, C++\n");
  5.     return 0;
  6. }
复制代码
  1. #ifndef _CPLUS_H_
  2. #define _CPLUS_H_

  3. int sayCplus();

  4. #endif
复制代码

C 代码,c.c和c.h

  1. #include<stdio.h>
  2. int sayC()
  3. {
  4.     printf("HI, This is C program\n");
  5.     return 0;
  6. }
复制代码
  1. #ifndef _C_H_
  2. #define _C_H_

  3. int sayC();

  4. #endif
复制代码

分别编译成动态库libCplus.so和libC.so
用nm 指令查看,可知函数sayCplus在动态库中被改名了。

这时若用c调用libCplus.so,或c++调用libC.so,会显示对函数xxx未定义的引用。

C调用C++动态库 ——即把C++以C方式编译
要实现C调用C++的动态库,需要使用"extern C"关键字。该关键字是C++之父在设计C++时,为兼容已存在的大量C代码而设定的方法。用该关键字将C++的函数包含起来,即可将C++按C语言的方式进行编译。
改写如上代码cplus.cpp

  1. #include<stdio.h>

  2. extern "C"
  3. {
  4. int sayCplus()
  5. {
  6.     printf("Hello, C++\n");
  7.     return 0;
  8. }
  9. }
复制代码

重新编译成动态库libCplus.so,该函数不会被再改名,就可以调用了。

注意:
<1>只在cpp中使用extern “C”,若其他c++代码包含了该头文件并调用动态库仍会报错,因为头文件中的函数是按c++方式(改名机制)寻找。
因此,若c++生成的动态库要供c 和 c++调用,需要将cpp和头文件中的函数都用extern "C"包含起来。
也可只在头文件中用extern "C"括起来,在cpp中包含该头文件,效果如上。
<2>用该方法C++就无法实现重载了。
<3>若C++函数的参数中使用了C中不存在的数据类型(如vector、string),或是包含了代码中的其他结构,则用extern "C"包含并不能编译通过。此时可以通过对该函数再封装一层,入参、出参确保是通用类型即可。

C++调用C动态库
C++动态库也要用到extern "C"关键字,但是用在头文件中。
先将C语言的头文件用extern "C"包起来,c++中include该头文件,即会以c的方式去寻找函数,即可实现c++调用c动态库。
注意:用extern "C"包涵后,该头文件就无法给c语言调用使用了,因此一般会加个宏定义__cplusplus,
判断是用c++的方式编译,则extern “C” 生效。
改后的头文件如下:

  1. #ifndef _C_H_
  2. #define _C_H_

  3. #ifdef __cplusplus
  4. extern  "C"
  5. {
  6. #endif

  7. int sayC();

  8. #ifdef __cplusplus
  9. }
  10. #endif

  11. #endif
复制代码

注意:该种方式,c的动态库并不用改变。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则