如果没有可用的 c++ 编译器,C 语言可以调用用 c++ 编写的 DLL 吗?
Posted
技术标签:
【中文标题】如果没有可用的 c++ 编译器,C 语言可以调用用 c++ 编写的 DLL 吗?【英文标题】:Can C language call the DLL written in c++ if not c++ compiler available? 【发布时间】:2013-07-29 21:52:52 【问题描述】:我有一个 DLL 来控制一些用 C++ 编写的外部设备。但是在开发中我使用 ANSI C(不支持 c++),所以我只能用纯 C 语法编译代码。
我想知道是否可以在我的 C 代码中加载用 C++ 编写的 DLL,是否依赖于 DLL 语言?有什么叫做 C++ DLL 或 C DLL 或 C# DLL 的东西吗?
如果是这样,是否意味着我们只能在同一种语言的代码中调用 DLL?我在网上搜索了一下,发现了一些关于在 C++ 环境中调用 C 的内容,他们建议使用 extern C
语句。但我认为我的情况正好相反,我需要在 C 中调用 C++,但是我的编译器不支持 C++,我该怎么做呢?
【问题讨论】:
有人可能会有更好的答案,但据我所知,您需要在 C++ 代码中使用extern c
构造,以免函数名称被破坏。否则,C++ 入口点将几乎不可读。根据编译器/平台的不同,调用约定也可能有所不同。我相信其他人会解决这些问题。
@Eric:这听起来对我来说是一个很好的答案......你让它成为一个答案怎么样?
如果您需要任何 C++ 运行时支持,那么您的情况就会很糟糕。为什么不能使用 C++ 编译器?
问谁给了你 DLL 使用 DLL 的正确方法是什么。
我正在使用labview CVI,它是一个纯C编译器,虽然它也支持MSVC并且可以在C++环境中编译,但是因为一切都在服务器上运行,我的IT不会安装任何其他编译器为此:(
【参考方案1】:
我想知道是否可以在我的 C 代码中加载用 C++ 编写的 DLL。
是的,只要满足所有运行时要求,您就可以使用 C 代码加载共享对象(或动态链接库),无论使用什么语言创建它。
是否依赖 DLL 语言?
共享对象本身是某种格式的二进制文件(即在 Linux 上它是 ELF)。它与创建它的语言无关。例如,理论上您可以在十六进制编辑器中编写一个 DLL,这样就不会有创建它的“语言”。
这是叫 C++ DLL 还是 C DLL 或 C# DLL?
理论上,如果您知道某个 DLL 是通过编译 C++ 代码创建的,那么您可以将其称为 «C++ DLL»。或者,如果它依赖于 C++ 特定的运行时库。然而,从系统的角度来看,它仍然是一个可执行的二进制对象,系统并不关心使用什么语言和/或编译器(如果有的话)来创建它。
……是不是只能在同一种语言的代码中调用DLL?
没有。
我在网上搜索了一下,发现了一些关于在C++环境中调用C的东西。
您需要了解Application Binary Interface (ABI),它描述了计算机程序与操作系统或其他程序之间的低级接口。对于 C++,除此之外,您还需要知道 symbol names are being mangled 是如何使用的异常机制。这取决于特定的机器/操作系统/编译器组合。
如果您知道这一点并且您的 «C++ DLL» 是可加载和可执行的(即所有运行时依赖项都存在),您几乎可以在 C 程序中托管该 DLL(即使该 DLL 没有通过 «extern 提供 C 接口) “C”» 语句)。例如,知道对象(即类)的大小、布局要求、错位的构造函数/析构函数名称(如果有),您就可以分配内存并构造该对象。然后,如果您知道方法名称的错位以及 «this» 指针是如何传递的,您就可以调用它们。
不要这样做!
话虽如此,这绝对是您需要尝试做的最后一件事。获得与该 DLL 的 ABI 匹配的适当 C++ 编译器,获得描述您要使用的接口的头文件并像普通人一样使用它要容易得多。自己实现该 DLL 的功能甚至比尝试破解更容易。所以,请尝试其他方法。正如好心人已经在 cmets 中建议的那样 — «问谁给了您 DLL 使用 DLL 的正确方法是什么»
祝你好运!
【讨论】:
【参考方案2】:这实际上取决于 DLL 中函数的实现。
如果函数暴露了 C++ 特性,例如返回类对象、获取 std::string
类型的参数(或任何其他类对象)或抛出异常,那么您将很难从 C 中以有意义的方式使用它。
但是,如果所有导出的函数都使用标准 C 接口(字符串是指向 char
的指针,没有例外 [1],没有返回类对象等),那么可以。但请记住,例如,如果 DLL “泄漏异常”,则没有人愿意使用它。
[1] 这实际上意味着,除非它 100% 确定调用不会引发异常(详情请参见下文),否则您必须在每个函数中使用 try code goes here catch(...) catch-all code here
。
在现代 C++ 中很难避免异常 - 例如,vector<int> v; ... v.push_back(42); ...
之类的无辜语句可能会导致 bad_alloc
异常。
总之,把所有事情都做好是相当复杂的——如果你真的想写一个 C++ DLL,那么你想从 C++ 中使用它。如果您想要一个 C 可调用的 DLL,那么通常用 C 编写它。
【讨论】:
【参考方案3】:DLL 在技术上不依赖于语言,因为它是一种可执行格式,并且可能任何语言都可以编译为调用 DLL 的机器代码,但在通常的实践中,它们是依赖于语言的,因为DLL 通常不包含足够的信息以供另一个可执行文件调用其函数。缺少的信息主要是调用约定,它决定了调用者(您的程序)和被调用者(DLL)如何操作机器寄存器和堆栈。据我了解,这些东西只是松散的标准化,编译器之间并不总是兼容。但是,您可以遵循某些约定来确保 DLL 在编译器之间“大部分”是可互操作的。
关于具体调用 C++ 的 C 代码,它是否(容易)工作取决于 DLL 导出的函数类型。如果它们是某个类的非静态成员函数,那么您可能会遇到困难。但是,如果它们是“常规”静态函数并且只使用与 C 兼容的类型作为参数和返回值,它甚至可能是直截了当的(尽管我认为仍然不能保证)。该信息应该在与 DLL 一起提供的头文件中找到。您还需要知道函数的“错位”名称,这可以使用诸如 dumpbin 之类的工具来确定(如果您安装了 Visual Studio 工具链,则可用)。
【讨论】:
【参考方案4】:如果 DLLL 使用 C++ 功能,那么最好的办法是使用 CVI 环境之外的 C++ 编译器制作包装 DLL。该 DLL 可以创建 C++ DLL 的 C 可调用接口,然后您可以将该 DLL 集成到 CVI 环境中。
【讨论】:
以上是关于如果没有可用的 c++ 编译器,C 语言可以调用用 c++ 编写的 DLL 吗?的主要内容,如果未能解决你的问题,请参考以下文章
C语言dev c++,选项release,debug,profiling啥意思?