使用 __declspec(dllimport) 导入函数调用

使用 可以更快地对调用添加批注__declspec(dllimport)。 访问导出的 DLL 数据始终需要 __declspec(dllimport)

导入 DLL 中的函数

以下代码示例演示如何使用 将 DLL 中的函数调用导入到应用程序中__declspec(dllimport)。 假设 func1 是一个函数,该函数位于与包含 main 函数的可执行文件分开的 DLL 中

如果没有 ,则给定以下代码__declspec(dllimport)

int main(void)
{
   func1();
}

编译器生成如下所示的代码:

call func1

链接器将调用转换为如下所示的内容:

call 0x4000000         ; The address of 'func1'.

如果 func1 位于另一个 DLL 中,则链接器无法直接解析此地址,因为它无法知道 func1 的地址。 在 32 位和 64 位环境中,链接器在已知地址中生成 thunk。 在 32 位环境中 thunk 如下所示:

0x40000000:    jmp DWORD PTR __imp_func1

此处 __imp_func1 是可执行文件的导入地址表中 func1 槽的地址。 链接器已知道所有这些地址。 加载程序只需在加载时更新可执行文件的导入地址表,即可使所有操作正常运行。

这就是使用 更好的原因:因为链接器在不需要时不会生成 thunk__declspec(dllimport)。 Thunk 使代码变大(在 RISC 系统上,它可以是多个指令),并可能降低缓存性能。 如果告诉编译器函数位于 DLL 中,则可以为你生成间接调用。

现在此代码:

__declspec(dllimport) void func1(void);
int main(void)
{
   func1();
}

生成此指令:

call DWORD PTR __imp_func1

没有 thunk 和 jmp 指令,因此代码很小且速度更快。 可以通过使用全程序优化,在没有 的情况下获得相同的效果__declspec(dllimport)。 有关详细信息,请参阅 /GL(全程序优化)

对于 DLL 中的函数调用,不需要使用间接调用。 链接器已知道函数的地址。 在间接调用之前加载和存储函数的地址需要额外的时间和空间。 直接调用速度更快且所需空间更小。 从 DLL 本身的外部调用 DLL 函数时,只需使用 __declspec(dllimport)。 生成 DLL 时,不使用 DLL 内的函数上的 __declspec(dllimport)

另请参阅

导入到应用程序中