使用C和C++接口编写库,以哪种方式包装?

Jac*_*lly 14 c c++ library-design

在准备一个库(让我们称之为libfoo)时,我发现自己面临以下困境:我是否将其编写为带有C包装器的C++库:

namespace Foo {
  class Bar {
    ...
  };
}

/* Separate C header. #ifdef __cplusplus omitted for brevity. */
extern "C" {
  typedef void *FooBar;
  FooBar* foo_bar_new() { return new Foo::Bar; }
  void foo_bar_delete(FooBar *bar) { delete bar; }
}
Run Code Online (Sandbox Code Playgroud)

或者将它编写为带有C++包装器的C库更好:

/* foo/bar.h. Again, #ifdef __cplusplus stuff omitted. */

typedef struct {
  /* ... */
} FooBar;

void foo_bar_init(FooBar *self) { /* ... */ }
void foo_bar_deinit(FooBar *self) { /* ... */ }

/* foo/bar.hpp */

namespace Foo {
  class Bar {
    /* ... */
    FooBar self;
  }

  Bar::Bar() {
    foo_bar_init(&self);
  }

  Bar::~Bar() {
    foo_bar_deinit(&self);
  }
}
Run Code Online (Sandbox Code Playgroud)

你更喜欢哪个?为什么?我赞成后者,因为这意味着我不必担心我的C函数会意外地冒出异常,而且我更喜欢C作为一种语言,因为我觉得它是一个较小的语义雷区.其他人怎么想?

编辑:这么多好的答案.谢谢大家.遗憾的是我只能接受一个.

Art*_*yom 19

小点:

当你编写C库时,它在任何地方都很有用 - 在C中,在C++中(包装器)和许多其他语言,如Python,Java使用绑定等,最重要的是它只需要C运行时.

当你编写C++包装器时,你还需要编写一个C包装器,但它并不像你想象的那么简单,例如:

c_api.h:

extern "C" {
  typedef void *Foo;
  Foo create_foo();
}
Run Code Online (Sandbox Code Playgroud)

c_api.cpp:

void *create_foo() 
{
    return new foo::Foo();
}
Run Code Online (Sandbox Code Playgroud)

怎么了?它可能会扔!并且程序将崩溃,因为C没有堆栈展开语义.所以你需要这样的东西:

void *create_foo() 
{
    try {
       return new foo::Foo();
    }
    catch(...) { return 0; }
}
Run Code Online (Sandbox Code Playgroud)

这适用于每个 C++ api函数.

所以我认为编写C库并提供单独的 C++包装器是更好的解决方案.

此外,它不需要与C++运行时库链接.

  • 另一个小问题:在一些拥有多个编译器供应商(例如Windows)的平台上,C ABI非常稳定并且可以跨供应商工作.C++ ABI往往是高度编译器供应商特定的,并且在某些情况下,获取使用一个C++编译器构建的库的二进制文件以与使用第二个C++编译器构建的客户端应用程序一起工作是一个棘手的问题.有关一种观点,请参阅[此MinGW wiki文章](http://www.mingw.org/wiki/MixingCompilers). (7认同)
  • 另请注意,C++是一种非常痛苦的语言.为自己无法做到的bozos制作C++包装器(在我看来这是非常糟糕的做法).C绑定是必须的. (2认同)
  • @MattJoiner`另请注意,C++是一种非常痛苦的语言.为自己做不了的bozos制作C++包装器`于2010年10月发布,现在2012年7月仍然没有人采取火焰诱饵?StackOverflow,我为你感到骄傲.*眼泪*. (2认同)

Eam*_*nne 8

使用您喜欢编写库的语言编写库.从技术上讲,您包装的方式并不重要.虽然一些C项目可能旨在排除不是C的库,而C++项目排除用C语言编写的库是很奇怪的,但这主要是一个哲学上的反对而不是实际反对.

在C++包装器中包装C可能会导致稍微更大的包装器,但C程序员更容易接受.

请注意,如果要分发二进制文件,C的简单性是有利的.


Ale*_*x F 5

如果您更喜欢用C语言编写,为什么还需要C++包装器?C++客户端可以使用C风格的API接口.另一方面,您更喜欢C++,有必要为C客户端安装C包装器.