2

我有一个 DLL 来控制一些用 C++ 编写的外部设备。但是在开发中我使用 ANSI C(不支持 c++),所以我只能用纯 C 语法编译代码。

我想知道是否可以在我的 C 代码中加载用 C++ 编写的 DLL,是否依赖于 DLL 语言?有什么叫做 C++ DLL 或 C DLL 或 C# DLL 的东西吗?

如果是这样,是否意味着我们只能在同一种语言的代码中调用DLL?我在网上搜索了一下,发现了一些关于在 C++ 环境中调用 C 的内容,他们建议使用extern C {}语句。但我认为我的情况正好相反,我需要在 C 中调用 C++,但是当我的编译器不支持 C++ 时,我该怎么做呢?

4

4 回答 4

2

我想知道是否可以在我的 C 代码中加载用 C++ 编写的 DLL。

是的,只要满足所有运行时要求,您就可以使用 C 代码加载共享对象(或动态链接库),无论使用哪种语言创建它。

DLL 语言依赖吗?

共享对象本身是某种格式的二进制文件(即在 Linux 上它是ELF)。它与创建它的语言无关。例如,理论上您可以在十六进制编辑器中编写一个 DLL,这样就不会有创建它的“语言”。

那叫 C++ DLL 或 C DLL 或 C# DLL 吗?

例如,如果您知道某个 DLL 是通过编译 C++ 代码创建的,那么理论上您可以将其称为 «C++ DLL»。或者,如果它依赖于 C++ 特定的运行时库。但是,从系统的角度来看,它仍然是一个可执行的二进制对象,系统并不关心使用什么语言和/或编译器(如果有的话)来创建它。

……这是否意味着我们只能在同一种语言的代码中调用 DLL?

不。

我在网上搜索了一下,发现了一些关于在 C++ 环境中调用 C 的内容。

您需要了解描述计算机程序与操作系统或其他程序之间的低级接口的应用程序二进制接口 (ABI) 。对于 C++,除此之外,您还需要知道符号名称是如何被破坏的,正在使用什么异常机制。这取决于特定的机器/操作系统/编译器组合。

如果您知道这一点并且您的 «C++ DLL» 是可加载和可执行的(即所有运行时依赖项都存在),您几乎可以在 C 程序中托管该 DLL(即使没有该 DLL 通过 «extern "C" 提供 C 接口) » 声明)。例如,知道对象(即类)的大小、布局要求、错位的构造函数/析构函数名称(如果有),您就可以分配内存并构造该对象。然后,如果您知道方法名称的错位以及 «this» 指针是如何传递的,您就可以调用它们。

不要这样做!

话虽如此,这绝对是您需要尝试做的最后一件事。获得与该 DLL 的 ABI 匹配的适当 C++ 编译器,获得描述您要使用的接口的头文件并像普通人一样使用它要容易得多。自己实现该 DLL 的功能甚至比尝试破解更容易。所以,请尝试其他方法。正如好心人已经在评论中建议的那样——“问谁给了你 DLL 使用 DLL 的正确方法是什么”

祝你好运!

于 2013-07-29T22:14:57.767 回答
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 编写它。

于 2013-07-29T22:19:16.527 回答
1

DLL 在技术上不依赖于语言,因为它是一种可执行格式,并且可能任何语言都可以编译为调用 DLL 的机器代码,但在通常的实践中,它们是依赖于语言的,因为 DLL 不' 通常不包含足够的信息以供另一个可执行文件调用其函数。缺少的信息主要是调用约定,它决定了调用者(您的程序)和被调用者(DLL)如何操作机器寄存器和堆栈。据我了解,这些东西只是松散的标准化,编译器之间并不总是兼容。但是,您可以遵循某些约定来确保 DLL 在编译器之间“大部分”是可互操作的。

关于具体调用 C++ 的 C 代码,它是否(容易)工作取决于 DLL 导出的函数类型。如果它们是某个类的非静态成员函数,您可能会遇到困难。但是,如果它们是“常规”静态函数并且只使用与 C 兼容的类型作为参数和返回值,它甚至可能是直截了当的(尽管我认为仍然不能保证)。此信息应该在与 DLL 一起提供的头文件中找到。您还需要知道函数的“错位”名称,这可以使用诸如 dumpbin 之类的工具来确定(如果您安装了 Visual Studio 工具链,则可用)。

于 2013-07-29T22:44:49.247 回答
0

如果 DLLL 使用 C++ 功能,那么最好的办法是使用 CVI 环境之外的 C++ 编译器制作包装 DLL。这个 DLL 可以创建一个 C++ DLL 的 C 可调用接口,然后你可以把这个 DLL 集成到 CVI 环境中。

于 2013-07-29T22:38:53.283 回答