5

在 C 语言中,我习惯于编写一个共享库,可以从任何希望使用它的客户端代码调用,只需链接该库并包含相关的头文件即可。但是,我读到 C++ 的 ABI太不稳定且不标准,无法可靠地调用其他来源的函数。

这让我相信,在 C++ 中创建与 C 一样通用的真正共享库是不可能的,但现实世界的实现似乎表明并非如此。例如,Node.js 公开了一个非常简单的模块系统,它允许使用该函数动态导出extern "C"纯 C++ 函数(不带)。NODE_SET_METHOD

C++ API 的哪些元素可以安全公开(如果有),以及允许 C++ 代码与其他 C++ 代码交互的常用方法是什么?是否可以创建可以公开 C++ 类的共享库?或者由于 ABI 不一致,是否必须为每个程序单独重新编译这些类?

4

3 回答 3

4

是的,C++ 互操作很困难并且充满了陷阱。冷硬规则是您必须使用完全相同的编译器版本和完全相同的编译器设置来构建模块并确保它们共享完全相同的 CRT 和标准 C++ 库。当一个模块使用与删除对象的模块不同的分配器分配对象时,打破这些规则往往会导致 C++ 类在分隔的两端没有相同的布局,并且内存管理出现问题。当代码使用错误的偏移量访问类成员并泄漏内存或损坏堆时,导致很难诊断运行时故障的问题。

Node.js 首先导出任何东西来避免这些问题。NODE_SET_METHOD() 不会做你认为它做的事情,它只是将一个符号添加到 Javascript 引擎的符号表中,以及在脚本中调用函数时调用的函数指针。此外,它是一个开源项目,因此使用相同的编译器和运行时库构建所有内容都不是问题。

于 2013-06-19T09:42:33.757 回答
1

这个

例如,Node.js 公开了一个非常简单的模块系统,它允许使用 NODE_SET_METHOD 函数动态导出纯 C++ 函数(没有 extern "C")。

错了,你可以看到他们extern "C"init()函数中使用了 an ,这显然是 node.js 正在调用的,然后将函数转发到他们想要的任何 C++ 函数上,这没有公开。

正如这个问题中所解释的,外部“C”声明如何工作?- 当编译器编译代码时,它会破坏函数名、类名和命名空间名。这样做的原因是很容易发生名称冲突,例如重载函数。

在这里阅读更多信息:http ://en.wikipedia.org/wiki/Name_mangling

引用和查找函数的唯一方法extern "C"是使用声明,这会强制编译器不破坏名称。即在上面的示例中,函数init将被调用init,因为函数foo将被调用类似的东西_ugAGE(我编造了这个,因为没关系,它不适合人类消费)

总之,您可以将任何 C++ 公开给任何其他语言,但库的入口点必须是一个或多个extern "C"'d 全局函数,因为它们是引用未修改名称的唯一方法。

于 2013-06-19T09:08:59.893 回答
0

C 和 C++ 标准都没有定义 ABI。这完全取决于实施。让共享/动态库为 C++ 工作变得更加困难的原因是,C++ 添加了类、多态性、模板、异常、函数重载、STL 等内容。

因此,对您而言,真正的信息来源是您的编译器文档,以及一组相应的库 API 指南,以避免为您的库构建的任何实现出现任何问题。在 C++ 中更难(指南集可能会比 C 大很多,并且您可能必须使用 C++ 的子集),但并非不可能。

于 2013-06-19T09:40:35.583 回答