如果C ++中的DLL不支持二进制封装,那么什么时候才可以使用它们呢?

记忆删除

因此,我正在阅读COM和DLL,好像,如果我要更新DLL的实现(如果所需的内存超过了旧的需求),则需要使用DLL重新编译程序。与更新的DLL。所以我只是想知道,什么时候使用DLL代替COM是正确的?重新编译所有程序似乎几乎是不可能的,仅仅是因为它们已经更新了依赖性。

另外,还有一个简短的问题:为什么.NET中二进制封装不成问题?我怎么能更改在.NET中找到的DLL,而不必重新编译我的旧项目,而无需使用pimpl / opaque指针和诸如此类的东西呢?

本·沃格特

二进制兼容性要求调用者和被调用者就通用ABI(应用程序二进制接口)达成协议。

在Windows和Linux上,操作系统都指定了用于C调用的标准ABI,该标准允许从任何其他语言到C库的调用。只要C ++仅DLL内部使用extern "C"并且外表面使用与C兼容的类型(例如,指针和基元以及与C兼容的类型的原始数据组合),这也使C ++对DLL的开发有用

在Linux和Windows上,C ++ ABI与C ++运行时库关联。在Linux上,人们习惯于自欺欺人地认为C ++共享对象也具有操作系统提供的ABI,因为只有一个广泛使用的C ++库-g ++ libstdc++,并且该库竭尽全力来保存相同的ABI。因此,C ++ 11之前的libstdc++ABI是事实上的标准,没有人遇到混合ABI的麻烦。现在,C ++ 11被迫libstdc++破坏二进制兼容性,而clanglibc++越来越流行,因此Linux开发人员面临着Windows开发人员长期以来所熟悉的问题。

在Windows上,从来没有C ++标准库以完全相同的方式占据主导地位,部分原因是操作系统供应商工具(Microsoft Visual C ++)的每个版本都引入了不兼容性。是的,有些事情基本上保持不变(名称修改),但其他事情发生了根本性的变化(分配器获得了低碎片堆支持,容器得到了调试迭代器,等等)。

具有讽刺意味的是,Windows上的ABI标准化现在比Linux 1上更好,因为Windows ABI指定了一种C ++功能-vtable布局-支持COM。

本机C ++的底线是您可以在DLL中自由使用它,但是为了进行解耦,DLL的公共表面只需要使用OS ABI中指定的功能-extern "C"名称,C兼容类型和(仅Windows) )仅由虚函数组成的抽象基类(无静态成员,无非静态数据,所有非静态函数都是虚函数,并且构造函数受到保护)。

但是,如果您可以进行耦合,那么您将获得更多功能。如果应用程序中的每个组件都同意.NET ABI,则其所有功能都将可用。.NET的ABI的开发考虑到了向后和向前的兼容性,它从C ++的不兼容性以及以前的尝试(例如Java)中吸取了教训。

由于.NET ABI非常稳定,因此与之耦合是一个可行的决定,就像许多与C ++ 11之前的Linux开发人员耦合一样 stdlibc++ABI。但是,如果您破坏了兼容性,则可能会丢失所有可重用的库,这就是为什么将耦合到任何特定的Windows C ++库视为一个坏主意的原因-升级编译器要求您拥有每个库的新版本。当即使只有一个组件卡在旧版本上也无法采用新的编译器时,您将失去对其他已切换组件的新开发的机会。这就是为什么Windows上的C ++ ABI耦合被广泛认为是一个非常糟糕的主意的原因。以及为什么库作者很少以二进制形式分发Linux代码-他们将其留给每个发行版来选择ABI,使用它进行一致地编译,并提供与其兼容的二进制软件包。

当然,这只能解决源代码外部的更改(对库类型的布局更改,参数传递顺序等)。如果您的源代码发生更改(例如,通过添加新的函数参数或更改类类型中的数据成员),则无论ABI有多好(明确规定/稳定),您都将不兼容。.NET通过两阶段编译系统避免了其中一些影响-依赖项更改时,确实会重新编译整个世界,因为JIT编译是在运行时完成的。但是即使在.NET中,某些更改(例如添加新的函数重载)也需要重新编译源代码才能生效。


实际上我不确定,是否也可以在Linux的操作系统级别上指定vtable-layout。重要的是Linux C ++二进制兼容性不再是通用的,这使许多实际上依赖于事实上的标准编译器提供的ABI的开发人员感到惊讶,同时还假设OS ABI永远保证了通用兼容性。因此,Windows开发人员已经学会了管理二进制兼容性的不足,处于更好的位置。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何用C读二进制文件++如果我在Java中产生的呢?

如果用户不是root用户,那么在使用hidepid = 2时,为什么只有执行权限的二进制进程仍隐藏在“ ps”中?

如果C中的语句

如果找不到值,则C搜索中的二进制搜索树无法返回消息

如果Java不支持参数化类型数组,那么Arrays.asList()如何与它们一起使用?

ParseFromArray 函数如何在 C++ 中工作以及如何使用它将二进制文件读入 protobuf?

是否可以使用`go install`而不是`go test -c`来编译测试二进制文件

如果a == b或a == c:vs如果a在{b,c}中:

否则,如果C中的语句

如果条件在C#中

如果以root身份执行的C程序通过调用system(someprog)执行另一个二进制文件,那么该程序也以root身份运行吗?

使用StringStream在C ++中读取二进制文件

什么时候可以在可执行二进制文件中编辑字符串?

如果clang ++和g ++不兼容ABI,则二进制共享库使用什么?

将二进制数转换为十六进制的C程序,如果它们等于十六进制字母,则不能转换两个以上的二进制数

gsl :: cstring_span不支持constexpr吗?如果没有,我为什么要使用它?

如果Android是Linux发行版,那么Ubuntu为什么不支持.apk文件?

C中的二进制除法

C中的二进制计数

C中的二进制补码

C中的二进制文件

如果从该二进制文件产生的任何进程仍在运行,是否可以在Linux中修改源二进制文件?

如果在Java中 如果在C ++中

如果某个进程从setuid二进制叉开始,并且子进程放弃了特权,那么仍可以信任该子进程吗?

我可以通过查看二进制文件中的符号来识别未使用的 C++ 头文件吗?

C ++ 14/17项目可以使用按C ++ 11标准编译的二进制库吗,还是需要重新编译源代码?

C打开一个文件以检查它是否为二进制文件,如果打印则为二进制文件

GPG:不支持的二进制格式

我可以在C或C ++中使用二进制文字吗?