4

我来自 Delphi 世界,在那里静态导入 DLL 函数非常容易。您需要做的就是指定函数名称和模块,如下所示:

function GetTickCount : DWORD; stdcall; external 'Kernel32.dll';

为什么我必须在 C++kernel32.lib中使用才能导入函数?为什么我不能像在 Delphi 中那样简单地告诉链接器导入该函数?

我知道这对你们中的许多人来说可能听起来很无聊,但是从 Delphi 进入 C++ 世界确实会让人感到困惑。

4

3 回答 3

8

C++ 工具链需要几个步骤来完成 Delphi 可以一步完成的工作。在 C++ 中声明外部 DLL 函数时,没有(标准)方法来指示该函数实际上可以在哪个命名的 DLL 中找到。就编译器而言,声明的函数很简单extern,必须有一个定义可以链接器可以在某处找到。

要将命名函数连接到可以在其中找到它的 DLL,C++ 工具链需要一个“导入库”,其中包含链接器知道如何处理的导入存根。当找到由导入存根定义的函数时,链接器为相应 DLL 中的特定函数名称创建一个 DLL 函数引用(如导入存根所示)。

在 Delphi 中,语言设计者允许程序员直接在源代码中指定相关联的 DLL。Delphi 编译器可以直接生成对外部 DLL 的引用,而无需使用导入存根步骤。

于 2012-10-12T06:44:30.803 回答
4

您的问题实际上只是 Microsoft C++ 编译器 (MSVC) 的问题,它需要使用“导入库”作为将符号(即函数名称)绑定到 DLL 中函数的序号的中间步骤。这本身不是 C++ 问题。这可以说只是 MSVC 编译器的另一个烦人的怪癖,但我对这种方案的动机知之甚少,无法评论它是否应该或可以改变。如果我没记错的话,C++Builder 编译器也可以使用这种机制,模仿 MSVC。

大多数其他编译器在链接和二进制接口方面与 GCC 的工作方式(GNU Compiler Collection)保持一致。而那些不需要这个额外的“导入库”,您只需将有问题的 DLL 指定为库的一部分,以与您的可执行文件链接。

顺便说一句,当谈到 C++ 链接器和 Delphi 链接器之间的差异时,您指出的这个问题只是冰山一角。它们在更深层次上是非常不同的。C++ 标准几乎要求链接器相当简单(由于“单独的编译模型”),只是连接点,可以这么说,而在 Delphi 中,链接器与编译器的联系更加紧密,并且通常更智能(并且快点)。

于 2012-10-12T07:05:24.240 回答
1

我刚刚向 QC 提交了以下功能请求:

QC #109493:添加编译器扩展来导入 DLL 函数,而不需要导入 .lib 文件

于 2012-10-13T01:05:38.913 回答