c++ - 我可以在 C 程序中使用用 C++ 创建的共享库吗?

标签 c++ c compilation shared-libraries

我正在使用 C 创建程序。但是,我需要使用许多只有 C++ 的 API 的库。那么,我是否可以在 C++ 中创建一个共享对象,然后使用 C 访问它的功能?

  1. 我要传递和返回的唯一数据是与 C 兼容的数据类型。
  2. 这里不能选择转换或迁移到 cpp。

如果无法连接这些代码,我如何从 C++ 代码获取信息到 C 代码? 我尝试从 C 调用 C++ 函数,但是当我包含 <string> 时,在链接过程中出现错误.那么当我从 C 调用 C++ 函数时,我应该只使用与 C 编译器兼容的代码吗?

C++ 头文件 cppfile.hpp

#ifndef CPPFILE_H
#define CPPFILE_H
    #ifdef __cplusplus
    extern "C" {
    #endif

    extern int myfunction(const char *filename);

   #ifdef __cplusplus
   }
   #endif
#endif

C++ 文件 cppfile.cpp

#include "cppfile.hpp"
#include <string>
int myfunction(const char *filename) {
    String S(filename);
    return 0;
}

C 文件 cmain.c

#include "cppfile.hpp"
int main(int argc, char **argv)
{
     int i = myfunction(argv[1]);
     printf("%d\n", i);
     return 0;
}

编译:

gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp

最佳答案

你想要更像这样的东西(这里我将使用一个更有意义的例子):

C/C++ 头文件 - animal.h

#ifndef ANIMAL_H
#define ANIMAL_H

#ifdef __cplusplus
class Animal {
public:
    Animal() : age(0), height(0) {}
    Animal(int age, float height) : age(age), height(height) {}
    virtual ~Animal() {}

    int   getAge();
    void  setAge(int new_age);

    float getHeight();
    void  setHeight(float new_height);

private:
    int age;
    float height; // in metres!
};
#endif /* __cplusplus */

#ifdef __cplusplus
extern "C" {
#endif
    struct animal; // a nice opaque type

    struct animal *animal_create();
    struct animal *animal_create_init(int age, float height);
    void           animal_destroy(struct animal *a);

    void           animal_setage(struct animal *a, int new_age);
    void           animal_setheight(struct animal *a, float new_height);
    int            animal_getage(struct animal *a);
    float          animal_getheight(struct animal *a);
#ifdef __cplusplus
}
#endif

#endif /* ANIMAL_H */

C++ 动物实现文件——animal.cpp

#include "animal.h"
#define TO_CPP(a) (reinterpret_cast<Animal*>(a))
#define TO_C(a)   (reinterpret_cast<animal*>(a))

void  Animal::setAge(int new_age) { this->age = new_age; }
int   Animal::getAge() { return this->age; }
void  Animal::setHeight(float new_height) { this->height = new_height; }
float Animal::getHeight() { return this->height; }

animal *animal_create() {
    animal *a = TO_C(new Animal);
    return a;
}

animal *animal_create_init(int age, float height) {
    animal *a = TO_C(new Animal(age, height));
    return a;
}

void animal_destroy(animal *a) {
    delete TO_CPP(a);
}

void animal_setage(animal *a, int new_age) {
    TO_CPP(a)->setAge(new_age);
}

void animal_setheight(animal *a, float new_height) {
    TO_CPP(a)->setHeight(new_height);
}

int animal_getage(animal *a) {
    TO_CPP(a)->getAge();
}

float animal_getheight(animal *a) {
    TO_CPP(a)->getHeight();
}

C 客户端代码 - main.c

#include "animal.h"
#include <stdio.h>

int main()
{
    // 6'0" 25yo (perhaps a human? :P)
    struct animal *a = animal_create(25, 1.83); 

    animal_setage(a, 26); // birthday
    printf("Age: %d\nHeight: %f", animal_getage(a), animal_getheight(a));

    animal_destroy(a);
    return 0;
}

C++ 客户端代码 - main.cpp

#include "animal.h"
#include <iostream>

int main()
{
    // 6'0" 25yo (perhaps a human? :P)
    Animal* a = new Animal(25, 1.83);
    a->setAge(26); // birthday
    std::cout << "Age:    " << a->getAge() << std::endl;
    std::cout << "Height: " << a->getHeight();

    delete a;
    return 0;
}

因此,当您编译库时,您使用 C++ 编译器编译 animal.cpp。然后,您可以使用 C 代码链接到它,并使用 animal_xxx 函数。

注意 struct animalAnimal 的使用。 Animal 是一个普通的 C++ 类型。这正是它的样子。另一方面,struct animal 是一种“不透明”类型。这意味着您的 C 程序可以看到它的存在,并且可以拥有一个,但它不知道里面有什么。它所知道的是它有一个接受 struct animal* 的函数。

在真正的库中,您会希望有内存分配的自定义点。因此,假设这是库 libjungle,您可能至少需要具有合理默认值的 jungle_setmallocjungle_setfree。然后,您可以在 libjungle 的 C++ 代码中设置全局 newdelete 以使用这些用户定义的函数。

关于c++ - 我可以在 C 程序中使用用 C++ 创建的共享库吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14917952/

相关文章:

java - 我需要做什么来解释这个 Java 程序?

c++ - 来自任务管理器的实际内存与在 C++ 单链表中手动计算的内存差异

c - 无法在 c 中的 while 循环期间/之后清除字符串

c++ - GCC:程序不适用于编译选项 -O3

c - 共享内存中的信号量、进程和递增变量

c - 在 C 代码中显示全局变量的依赖关系

c# - 将可空枚举与其底层原语进行强制转换时出现奇怪/不必要的编译器输出

c++ - 作为函数模板参数的基本类型

c++ - 在C++中接受多个字符串作为输入

c++ - 通过Visual C++访问串口