C和C++程序互相调用方案
创始人
2025-05-28 12:28:47

C++程序调用C函数

项目实际开发需求需要在C++程序中调用c语言实现的库,那么需要怎么实现呢?

原理:C++函数为了支持函数重载,g++编译器会对函数名进行修饰,而C函数编译的符号表中只是函数名。同样的代码用C编译器(gcc)和C++编译器(g++)编译产生的函数名不同,导致C++连接找不到C语言的函数,所以C++程序中直接C函数是不能直接实现的,需要通过某种处理

下面通过一个例子简单说明C++和C编译原理的不同之处

add.c#include "add.h"int add(int m, int n)
{return m + n;
}add.h#ifndef ADD_H__
#define ADD_H__
int add(int m, int);
#endif

上面源码用gcc编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m1qdyXwu-1678875989098)(C:/Users/100011704/Desktop/md%E6%96%87%E6%A1%A3/images/12.png)]

同样源码使用g++编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yGss3thl-1678875989098)(C:/Users/100011704/Desktop/md%E6%96%87%E6%A1%A3/images/23.png)]

解决:

extern "C"的主要作用就是为了实现c++代码能够调用其他c语言代码。加上extern "C"后,这部分代码编译器按c语言的方式进行编译和链接,而不是按c++的方式。

我们只要在c的.h文件下进行如下操作,再在c++文件中调用c的头文件,就可以链接成功。

c文件的.h文件代码如下

add.c#include "add.h"int add(int m, int n)
{return m + n;
}add.h#ifndef ADD_H__
#define ADD_H__#ifdef __cpluscplus
extern "C"{
#endifint add(int m, int);#ifdef __cpluscplus
};
#endif#endif

(extern"C"是C++特有的,所以上面加上宏__cpluscplus判断当使用C++编译时才加上extern "C"关键字)

下面写个简单的c++程序去调用c函数

main.cpp

#include 
#include "add.h"int main()
{std::cout << add(1,2)<

编译:g++ main.cpp add.c -o main

运行

到这里已经完成C++去调用C程序函数

C程序调用C++函数

场景:基本我们linux底层开发都是基于C语言开发,而上层应用基于C++开发,现在我们有C程序需要调用C++中的功能函数,该如何实现呢?

假设我们有一个C++类 Robot,在文件 robot.hrobot.cpp 中定义。Robot 类中有个成员函数 sayHi() 我们想在C程序中调用这个函数。

C++部分代码如下:

robot.h#pragma once#include class Robot
{
public:Robot(std::string name) : name_(name) {}void sayHi();private:std::string name_;
};------------------------
robot.cpp#include #include "robot.h"void Robot::sayHi()
{std::cout << "Hi, I am " << name_ << "!\n";
}

我们编译生成g++的动态库

g++ -fpic -shared robot.cpp -o librobot.sonm librobto.so     #nm命令可以查看动态库的符号表

此时完成c++动态库的生成,如果我们现在有C程序想要根据C++动态库和头文件直接使用是不行的(因为动态库是基于C++编译的不能修改编译方式的,C编译器并不能识别)

解决方案:
直接调用不可行,可以定义一个中间类完成转换

如下定义一个中间类Middle的接口,定义在Middele.h和Middle.cpp,该接口会定义一个C函数 Robot_sayHi(const char *name), 这个函数会创建一个类 Robot 的实例,并调用 Robot 的成员函数 sayHi()。

Middele.h
#pragma once#ifdef __cplusplus
extern "C" {
#endifvoid Robot_sayHi(const char *name);#ifdef __cplusplus
}
#endif-----------------------------------------
Middle.cpp#include "Middle.h"
#include "robot.h"#ifdef __cplusplus
extern "C" {
#endif// 因为我们将使用C++的编译方式,用g++编译器来编译 robot_c_api.cpp 这个文件,
// 所以在这个文件中我们可以用C++代码去定义函数 void Robot_sayHi(const char *name)(在函数中使用C++的类 Robot),
// 最后我们用 extern "C" 来告诉g++编译器,不要对 Robot_sayHi(const char *name) 函数进行name mangling
// 这样最终生成的动态链接库中,函数 Robot_sayHi(const char *name) 将生成 C 编译器的符号表示。void Robot_sayHi(const char *name)
{Robot robot(name);robot.sayHi();
}#ifdef __cplusplus
}
#endif

同样用编译C++代码的方式进行编译

g++ -fpic -shared  Middle.cpp -L. -lrobot -o libmiddle.so

通过nm libmiddle.so 命令可知动态链接库提供了一个C函数 Robot_sayHi(const char *name),我们可以在C程序中调用它了

下面就可以写一个测试的c文件完成调用了

main.c

-

使用C程序的编译方式,用 gccmain.c 进行编译

gcc main.c -L. -lmiddle

通过objdump -t main命令可以看到可以看到 gcc 编译出的函数符号和 libmiddle.sog++ 编译器编译出的函数符号一致。这样最终在我们的C程序中可以正确的链接到动态库中的Robot_sayHi(const char *name) 函数。

运行可能出现如下报错:

./main: error while loading shared libraries: libmiddle.so: cannot open shared object file: No such 

运行可能找不到动态库的路径导致报错,可以配置/etc/ld.so.conf 或者~/bashrc或者/etc/profile配置文件既可以

可参考如下连接:

https://blog.csdn.net/weixin_42310458/article/details/125180410

相关内容

热门资讯

吸猫伐是什么意思 吸猫是吸哪里 作为铲屎官,相信对于网络上流行的各种与猫咪相关的梗都是了然于心的,什么吸猫啦,撸猫啦,云养猫啦……等...
亚洲都有哪些国家 亚洲都有哪些... 亚洲,我们非常熟悉的大洲,因为我国就是位于亚洲。亚洲是全球面积最大、人口最多的大洲。目前亚洲有48个...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
重庆属于哪个省份的 重庆在中国... 重庆有多大,大到超出我们的想象,重庆作为我国4个直辖市之一,印象里应该跟京津沪面积差不多,可事实上却...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...