如何从C中调用C++函数
转载来自:https://zhuanlan.zhihu.com/p/361485807
假设我们有一个C++类 Robot,在文件 robot.h 和 robot.cpp 中定义。Robot 类中有个成员函数 sayHi() 我们想在C程序中调用这个函数。
robot.h
#pragma once #include <string> class Robot { public: Robot(std::string name) : name_(name) {} void sayHi(); private: std::string name_; };
robot.cpp
#include <iostream> #include "robot.h" void Robot::sayHi() { std::cout << "Hi, I am " << name_ << "!\n"; }
我们用编译C++代码的方式,使用 g++ 编译器对这个类进行编译,此时类 Robot 并不知道自己会被C程序调用。
g++ -fpic -shared robot.cpp -o librobot.so
接下来用C++创建一个C的接口,定义在 robot_c_api.h 和 robot_c_api.cpp 中,这个接口会定义一个C函数 Robot_sayHi(const char *name), 这个函数会创建一个类 Robot 的实例,并调用 Robot 的成员函数 sayHi()。
robot_c_api.h
#pragma once #ifdef __cplusplus extern "C" { #endif void Robot_sayHi(const char *name); #ifdef __cplusplus } #endif
robot_c_api.cpp
#include "robot_c_api.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 robot_c_api.cpp -L. -lrobot -o librobot_c_api.so
现在我们有了一个动态链接库 librobot_c_api.so, 这个动态链接库提供了一个C函数 Robot_sayHi(const char *name),我们可以在C程序中调用它了。
main.c
#include "robot_c_api.h" int main() { Robot_sayHi("Alice"); Robot_sayHi("Bob"); return 0; }
使用C程序的编译方式,用 gcc 对 main.c 进行编译
gcc main.c -L. -lrobot_c_api
可以看到 gcc 编译出的函数符号和 librobot_capi.so中 g++ 编译器编译出的函数符号一致。这样最终在我们的C程序中可以正确的链接到动态库中的Robot_sayHi(const char *name) 函数。