为C ++库编写C包装器?

时间:2015-09-08 04:48:29

标签: c++ c api cross-platform standards

C ++ 11有sleep_for。但是C标准没有等价物。

我想我可以编写一个包装器来从C调用这样的C ++函数。

还有像Boost Filesystem和Asio这样的有用库。这些更复杂,但我也可以编写包装器。

它可以重新发明轮子吗?这可能是一个坏主意吗?

2 个答案:

答案 0 :(得分:2)

这个问题是,如果你想编写调用Boost函数的C包装器,如果抛出异常你会怎么做?你基本上必须在它到达C之前在调用者中吞下它,但是将它正确地报告给C有点尴尬然后有很多类型的例外。

通常人们在特别想要额外的可移植性时使用C而不是C ++,或者由于某种原因无法提供所有C ++依赖。如果你想编写一个使用boost :: filesystem的C程序,为什么不把它编译成C ++呢?你可以用更少的异常处理锅炉板代码来编写,而且可以减少错误。

答案 1 :(得分:2)

zeroMQ这样做。该库是用C ++编写的,但库API是C接口。原则上,您将类隐藏在对象大小的内存块中并传递void*。对于一些简单的功能,例如sleep_for,你可以创建一个包装函数。在标题中,声明

extern "C" {void sleep_for(int duration);}

在您的cpp文件中,请按std::this_thread::sleep_for

执行此操作
sleep_for(int duration) {std::this_thread::sleep_for( std::chrono::milliseconds(duration);}

对于类,您需要C函数来创建新对象,破坏它,当然还需要调用成员函数。对于A类,这可能如下所示:

C头文件“A_C_API.h”:

extern "C" {
     enum {SIZE_OF_A = 4};
     typedef char[SIZE_OF_A] a_class;
     a_class initA(void* a, int x);
     void destructA(void* a);
     int callGet(void *a);
}

C++ source file:

class A {
public:
    A(int i): x{i} {}
    int get() const {return x;}
private:
    int x;
};

static_assert( SIZE_OF_A == sizeof(A), "size mismatch!");

void initA(void* a, int x) {
    new (a) A(x);
}

void destructA(void* a) {
    static_cast<A*>(a)->~A();        
}

int callGet(void *a) {
    return static_cast<A*>(a)->get();
}

在您的C应用程序中,您可以

#include "A_C_API.h"
int main(int argc, char* argv[]) {
    a_class obj;
    initA(&obj);
    printf("%d", callGet(&obj) );
    destructA( &obj );
    return 0;
}

您必须捕获异常并将其转换为某些C错误处理。您还必须处理某些平台上的对齐问题,尤其是SPARK平台。为简单起见,我省略了这一点,但你可以看看zeromq标头如何做到这一点。