如何从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) 函数。

参考来源 

posted @ 2022-06-30 10:45  冰糖葫芦很乖  阅读(1605)  评论(0编辑  收藏  举报