C++快速入门之 __declspec(dllimport)

我看到了这样的Qt源代码:

class Q_CORE_EXPORT QBasicAtomicInt
{
public:
...
};

哪个Q_CORE_EXPORT宏定义如下:

define Q_DECL_IMPORT __declspec(dllimport)

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

最佳答案

__declspec 是Microsoft特定的属性,允许您指定存储类信息。
(Nitpicker的一角:但是,许多其他编译器供应商(例如GCC)现在支持此语言扩展,以与针对Microsoft编译器编写的已安装代码库兼容。有些甚至提供附加的存储类属​​性。)

可以指定的那些存储类属性中的两个是dllimport和dllexport。这些向编译器指示分别从DLL导入或导出函数或对象。

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

由于显而易见的原因,__declspec(dllimport)和__declspec(dllexport)通常会相互配对。您可以使用dllexport将符号标记为从DLL导出,并且可以使用dllimport将该导出的符号导入另一个文件。

因此,由于在编译DLL和使用DLL接口(interface)的客户端代码中通常都使用相同的头文件,因此定义宏是一种常见的模式,该宏在编译时会自动解析为适当的属性说明符。例如:

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

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

大概就是Q_CORE_EXPORT宏所做的,解析为Q_DECL_IMPORT或Q_DECL_EXPORT。


1. 用法

在 VS 的“预编译”选项里定义_EXPORTING宏

#ifdef _EXPORTING
#define API_DECLSPEC __declspec(dllexport)
#else
#define API_DECLSPEC __declspec(dllimport)
#endif

API_DECLSPEC void HelloWorld();</pre>

2. 作用

2.1.

__declspec(dllexport)用于导出符号,也就是定义该函数的dll;__declspec(dllimport)用于导入,也就是使用该函数。

因为这个头文件既要被定义该函数的dll包含,也要被使用该函数的程序包含,当被前者包含时我们希望使用 __declspec(dllexport) 定义函数,当被后者包含时我们希望使用 dllimport。

2.2.

假设你的A(EXE或DLL)需要调用B(DLL)中的某个导出函数:__declspec(dllexport) void HelloWorld();

不用宏,在项目A中直接包含这个头文件,编译、运行……OK。

打开Dependency Walker(其它合适的工具也可以),打开A(.EXE或.DLL)文件,在左边树中选择根节点,A文件也有导出符号”HelloWorld”

2.3.

不使用 declspec(dllimport) 也能正确编译代码,但使用 declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。

2.4.

导入全局、静态或者类成员变量需要__declspec(dllimport)。

#define DllImport __declspec(dllimport) 
DllImport int j;</pre>

__declspec(dllexport)是用于避免需要自己写 DEF 文件的。编译器会为被declspec(dllexport)修饰的函数自动添加一个导出函数入口。如果你在其他模块中包含 declspec(dllexport)的头文件,这些项目的导出表中也会生成一个同名导出函数。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!