通过C绑定来公开C 库

Exposing a C++ library via C bindings

本文关键字:绑定 通过      更新时间:2023-10-16

是否有任何可用的准则,习惯,最佳实践...如何通过C绑定来公开C 库(作为库的一部分编译)。

目的是不是修改C 类。

假设以下两个C 类

class B {
   public:
    std::vector<int> list();
    std::string toString();
};
class A {
   public:
    explicit A(size_t size);
    B getB();
};

将其视为C API的"最佳"方法是什么?处理指针和实例化对象的功能列表,回调?有没有公认的命名约定的列表?

extern "C" {
    A* A_new(size_t size);
    void A_delete(A* a);
    B* A_getB(A *a);
    void B_delete(B* b);
    ...
}

(注意:要求公认的实践和惯例和/或工具是不是征求意见,而是实际反馈)

我的经验是,要回答的基本问题是c 对象是某种类型的单例,还是在接口的C侧有多个实例。

如果它们是单例,则C接口可以是一组函数,并且所有管理,对象手柄和其他位都保存在接口的C 侧。库的用户不需要任何一种引用特定C 对象的方法。

但是,如果C 对象有多个实例,则必须确定如何处理这些多个对象及其寿命的决定。我看到的主要两种方法是(1)提供一个指向C 对象的指针到接口的C侧,或(2)向C 对象提供一个句柄,并用句柄引用AC 方面的管理区域。

我个人喜欢手柄方法,因为那时现代的C 实践可以用于管理对象的寿命。对象存储在某些C 容器中,该容器具有提供给C接口的唯一手柄或标识符,并且C 侧拥有对象。C侧正在通过C接口对对象上的特定操作。

C接口可能会在映射到单个C 对象方法的唯一函数之间或更通用的函数,该功能通过指定C 对象方法的唯一标识符,将其构成命令标志的内容。

在第一个替代方案中,C 对象的方法将作为C接口函数公开,在多个实例的情况下,将指向C 对象的指针或对象的句柄。C接口函数,用C 编写,然后使用正确的参数调用实际的C 对象方法。因此,这只是将参数转发到C 对象的C接口函数。

在第二个替代方案中,C 接口函数必须使用查找表或switch或类似的方法来确定要调用的方法。可以在接口中指定参数,也可以使用可变参数。如果使用了可变参数,则您存在解析参数列表,提交参数然后调用C 对象方法的问题。

另一个考虑因素是命名和名称空间混乱。在C中,有传统的三个字母前缀方法来命名外部命名,尽管在大多数情况下,更多的字符更有意义。

但是,我真正喜欢的方法是拥有一个外部结构,其中是构成接口的C函数的功能指针。通过执行此操作,您可以将结构命名为图书馆有意义的东西,然后您可以随意命名实际功能指针。

实际的C接口函数是源文件中的static,它仅公开包含函数指针的结构。结构本身是一个全局,当在包含C接口函数的源文件的底部定义时将其初始化。

您提出的问题通常是处理此问题的最佳方法。您的函数可以将指针返回到新分配的对象,一组函数,该功能采用该指针并执行各种操作,还有一个将指针拿到指针并释放内存的功能。

您唯一需要添加的是声明与C:

兼容的类型
typedef struct A A;
typedef struct A B;

您不应该在C接口中公开STD类型(B类中的公共成员),因为C ABI未标准化,您可能最终会遇到很难找出的错误当API消费者使用不同的编译器版本时。

例如,在您的代码中,我将重写B如下:

class B {
   public:
    int* list(); // or write your own implementation for a vector type which you ship with the api
    const char* toString();
};