DLL 用 C 编写,与用 C++ 编写的相同

DLL written in C vs the same written in C++

本文关键字:C++ 与用 编写 DLL      更新时间:2023-10-16

我今天正在和一个同事讨论。他声称用C编写DLL将允许任何其他应用程序(用任何语言编写(使用该DLL。但是,如果该 DLL 是用C++编写的,则可以使用该 DLL 的应用程序数量是有限的(可能是由于语言限制(。

  1. 他这么说对吗?
  2. 如果你要编写一个DLL,应该被用各种语言编写的各种应用程序使用(但在同一平台上;让我们暂时忘记可移植性(,你会用C/C++编写它吗?为什么?

我希望这个问题不是大猩猩与鲨鱼的问题。如果是,请关闭它。

大多数语言都提供了一种从DLL调用C函数的(简单(方法。C++的情况并非如此,因为C++ ABI(C++函数的二进制接口(是特定于供应商的。

除此之外,几乎不可能与使用高级C++构造(如模板或 STL(C++ DLL 进行交互。

但是,DLL 的内容可以用C++编写,您只需要确保您的接口符合 C 标准。为此,请勿在接口中使用C++构造,并将声明括为:

#ifdef __cpluscplus
extern "C" {
#endif
/* You declarations here */
#ifdef __cpluscplus
}
#endif

。这样,您就可以使用 C 接口包装C++库。

编辑:正如Mats Petersson所写,不要忘记确保在包装器中处理每个可能的C++异常。

1(如果DLL提供的接口确实是一个C++接口,那么是的,这使得其他语言很难(如果不是不可能的话(与DLL接口。

C++的接口比 C 更复杂,因为类的结构(this传递的指针、虚拟函数指针/VTABLE 布局(和异常处理(其中被调用的代码必须以某种方式处理异常发生的事实,并且要做到这一点,代码需要能够"展开"引发异常的代码的调用堆栈并销毁在直到它找到一个catch - 如果 DLL 中的调用堆栈中不存在,你会遇到问题 - 这种展开不是C++标准的一部分,因为该标准不希望限制处理器需要/应该实现哪些架构和哪些功能C++超过必要的(。在 DLL 中捕获异常将解决此处的问题。

换句话说,如果该语言不是C++[并且可能来自调用代码的同一供应商],则需要对调用它的任何语言的C++进行一些处理。这可能会变得非常复杂。

任何C++对象都需要从调用代码中的相关语言翻译过来。对于与 C 语言通用的基本类型,这通常不是问题,但类、结构等必须与本地语言兼容的东西相匹配。

另一方面:C 函数非常容易接口:将参数放在堆栈上,调用函数,并在返回时清理参数。没有发生任何奇怪的事情,没有隐藏的功能参数,不需要展开堆栈。唯一有点复杂是返回struct(大于一定大小(的函数 - 但这在 C 语言中是一个非常特殊的情况.C 的"对象"要简单得多,大多数语言的类型都与基本的 C 语言类型非常对应(但 C 样式struct仍然会引起一些有趣的问题,如果"巧妙地"使用它union可以成为一个真正的 challeng(。

2(选择语言是一项复杂的业务,这在很大程度上取决于DLL应该如何使用或它应该提供什么样的接口,以及它本身应该连接到什么接口 - 如果你的DLL接口到另一个C++DLL(或其他一些C++代码(,那么你可能想要使用C++。但是有一些方法可以生成具有 C 接口的 C++ DLL,方法是对接口函数使用 extern "C"(并确保没有任何东西throws越过"C",因为这肯定会引起问题(。

结论:显然,通过将接口限制为"仅使用C++",那么还有一个进一步的复杂性,因为任何使用库的人,比如C,Python或Lisp[所有这些都可能相当容易地调用C函数],用户将不得不将C++代码包装在C语言包装器中。是的,这是可以做到的,并且当C++中有一些非常好的库可用时,有人想要连接到具有可用 C 样式界面的语言时,会经常使用。它与"在 DLL 中提供 C 到 C++ 接口"的解决方案几乎相同,只是它不是由 DLL 的生产者提供的。

每种语言都有自己的特性,如调用约定、堆栈设置和其他东西。每当你尝试处理跨越语言边界的函数调用时,你都必须处理这个问题。编译器通常支持多种调用约定,因此您必须确保定义和编译正确,然后可以使用任何语言与其他模块进行通信。这样的说法,即从一种语言或另一种语言中更容易或更难做到,这是不正确的,因为您总是必须在某个时候处理这个问题。

我选择最适合我的任务的语言,而不是相反。当我编写GUI应用程序时,我通常使用Java,因为它让我专注于解决方案而不是跟踪内存。:)当我想要性能时,我会使用 C 或 C++ 甚至汇编程序,因此语言的选择取决于我打算用它做什么或我的环境看起来如何。

相关文章: