__declspec(dllimport) 真正的含义是什么?

107
我看到Qt的源代码是这样的:
class Q_CORE_EXPORT QBasicAtomicInt
{
public:
...
};

哪个 Q_CORE_EXPORT 宏定义的内容如下:

define Q_DECL_IMPORT __declspec(dllimport)

那么__declspec(dllimport)到底是什么意思呢?


2
可能是为什么/何时不需要使用__declspec(dllimport)的重复问题。 - Hans Passant
4个回答

149

__declspec 是一个微软特有的属性,允许你指定存储类信息。
(挑剔者角落:然而,其他一些编译器供应商(例如GCC)现在为了与针对 Microsoft 编译器的代码进行兼容而支持此语言扩展。甚至提供了额外的存储类属性。)

其中可以指定的两个存储类属性是 dllimportdllexport。它们分别表示从 DLL 中导入或导出函数或对象。

更具体地说,它们定义了 DLL 的客户端接口,而不需要模块定义 (.DEF) 文件。大多数人发现使用这些语言扩展比创建 DEF 文件要容易得多。

由于明显的原因,__declspec(dllimport)__declspec(dllexport) 通常是配对使用的。你使用 dllexport 将符号标记为从 DLL 导出,并使用 dllimport 在另一个文件中导入该导出的符号。

由于这个原因,并且通常在编译 DLL 和使用 DLL 接口的客户端代码时都使用相同的头文件,所以定义一个宏,在编译时自动解析为适当的属性说明符是一种常见的模式。例如:

#if COMPILING_DLL
    #define DLLEXPORT __declspec(dllexport)
#else
    #define DLLEXPORT __declspec(dllimport)
#endif

然后使用DLLEXPORT标记应该被导出的所有符号。

可以假设Q_CORE_EXPORT宏的作用是解析成Q_DECL_IMPORT或者Q_DECL_EXPORT


11
据我所知,微软发明了__declspec符号作为C++语言的扩展。我相信GCC现在也支持它,但这主要是为了与微软的编译器兼容。我不明白“MS-specific”和“compiler specific”有什么不同。微软编写了一个C++编译器,很多人使用它。它随同Visual Studio一起提供。 - Cody Gray
1
__declspec()dllimport/dllexport都不是专门针对微软编译器的。__declspec被许多不同供应商的编译器用于支持C++语言本身的特定扩展。几乎所有支持微软平台的C++编译器都支持dllimport/dllexport扩展,但它们绝不是唯一可用的扩展。 - Remy Lebeau
9
微软有一个编译器,名为“Microsoft C/C++ 优化编译器”,即cl.exe。许多人错误地将Visual Studio称为编译器,但它是一个集成开发环境。我不知道为什么人们要对“微软特定”这个词斤斤计较。它并不意味着一个“MS环境”(无论那是什么),当然也不意味着“Windows”。是的,其他编译器供应商现在支持这种扩展,以兼容针对微软编译器编写的代码库。正如我之前所说,就我所知,微软发明了这个语法。这就是这里要表达的观点。 - Cody Gray
2
@CodyGray:仅仅是微软发明它还不够。然而,微软发明它,没有包含它的标准,其他人只是为了兼容性而实现它,并且它主要(如果不是唯一)用于针对Microsoft Windows的程序,这些因素共同构成了一个非常有力的理由,称其为“Microsoft特定”。 - celtschk
8
这是一个很棒的答案,尤其是关于“因为同一个头文件通常用于编译DLL和客户端代码”,这一部分!这使得导入/导出相关的每个方面都变得清晰易懂。 - Ela782
显示剩余7条评论

35

__declspec(dllimport)是存储类说明符,告诉编译器一个函数、对象或数据类型在外部DLL中定义。

使用对应的 __declspec(dllexport) 导出一个函数、对象或数据类型到DLL中。


8
好的。最终,在阅读了两个小时后,我找到了最令人满意、最简洁、准确表达我想要的观点的陈述。 - el psy Congroo

8
__declspec(dllexport)告诉编译器通知链接器需要将这些符号放在导出表中(在编译.dll时),并将这些符号放在导入库.lib中。当编译与.dll链接的程序时,__declspec(dllimport)告诉编译器产生一个rip相对的内存间接调用(链接器将填充以指向导入表解析)而不是通常的相对直接指令到未定义函数(由于它不能修改指令,链接器插入thunk的相对地址,然后创建thunk,在其中放置rip相对的内存间接跳转到导入表中的函数指针)。这是代码大小和速度的优化。导入库.lib告诉链接器哪些符号由.dll导出,并用作基于这些符号与匹配的extern符号表条目的交集来创建导入表的指南,并在.text段中创建任何必要的thunk。

https://learn.microsoft.com/en-us/cpp/build/importing-function-calls-using-declspec-dllimport?view=vs-2019 https://learn.microsoft.com/en-us/cpp/build/importing-data-using-declspec-dllimport?view=vs-2019 https://dev59.com/Ym855IYBdhLWcg3wMBLV#4490536


-2

这意味着函数的定义在动态库中。 请参考文档获取更多详细信息和示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接