如何從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) 函數。

參考來源 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章