c++代码能可靠地与其他c++代码交互吗?
Can C++ code reliably interact with other C++ code?
在C中,我习惯于编写一个共享库,只要连接库并包含相关的头文件,就可以从任何希望使用它的客户端代码调用该库。然而,我读到c++的ABI太不稳定,不标准,无法可靠地从其他来源调用函数。
这将使我相信在c++中创建像C一样通用的真正的共享库是不可能的,但现实世界的实现似乎表明情况并非如此。例如,Node.js公开了一个非常简单的模块系统,允许使用NODE_SET_METHOD
函数动态导出普通的c++函数(不含extern "C"
)。
c++ API的哪些元素是可以安全公开的,如果有的话,允许c++代码与其他c++代码交互的常用方法是什么?是否有可能创建可以公开c++类的共享库?或者由于不一致的ABI,必须为每个程序单独重新编译这些类?
是的,c++互操作很困难,而且充满了陷阱。冷硬性规则是必须使用完全相同的编译器版本和完全相同的编译器设置来构建模块,并确保它们共享完全相同的CRT和标准c++库。打破这些规则往往会让你的c++类在划分的两端都没有相同的布局,并且当一个模块使用与删除对象的模块不同的分配器分配对象时,会出现内存管理问题。当代码使用错误的偏移量访问类成员并泄漏内存或破坏堆时,导致很难诊断运行时故障的问题。
Node.js避免了这些问题,首先不导出任何东西。NODE_SET_METHOD()不做您认为它做的事情,它只是向Javascript引擎的符号表添加一个符号,以及在脚本中调用函数时调用的函数指针。此外,它是一个开源项目,所以用相同的编译器和运行库构建所有不是问题。This
例如,Node.js公开了一个非常简单的模块系统,允许可以动态导出普通c++函数(不带外部"C")使用NODE_SET_METHOD函数。
是错误的,你可以看到他们在init()
函数中使用了一个extern "C"
,这显然是node.js正在调用的,然后将函数转发到他们想要的任何c++函数,这是不暴露的。
正如在这个问题中所解释的,extern "C"申报工作吗?当编译器编译代码时,它会混淆函数名、类名和命名空间名。这样做的原因是很容易出现名称冲突,例如重载函数。
在这里阅读更多内容:http://en.wikipedia.org/wiki/Name_mangling
引用和查找函数的唯一方法是使用extern "C"
声明,这强制编译器不修改名称。例如,在上面的例子中,函数init
将被称为init
,而函数foo
将被称为类似_ugAGE
的东西(我编了这个,因为它无关紧要,它不是供人类使用的)
extern "C"
'd全局函数,因为它们是引用未修改名称的唯一方法。
C和c++标准都没有定义ABI。这完全取决于执行。让共享/动态库在c++中工作更困难的原因是c++添加了类、多态性、模板、异常、函数重载、STL等东西。
所以,对你来说,真正的信息来源是编译器的文档,以及一组相应的库API指南,以避免与你的库将为之构建的任何实现有关的任何问题。这在c++中比较困难(指南集可能比C要大得多,而且您可能不得不使用c++的一个子集),但并非不可能。
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么在这个代码结束循环中没有得到结束
- 在c代码之间共享数据的最佳方式
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值