记一次 __declspec(dllimport) 导出函数报错

1,026 阅读2分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

遇到了一个警告

warning C4273 "function": DLL 链接不一致

问题出在文件中的两个定义在使用 dllimport时有所不同。 也就是所谓的重复定义问题。

在这之前我们先了解一下 dllimport 一般而言 dllimport 和 dllexport 是 Microsoft 专用 的, dllexport 和 dllimport 可以使用它们从 DLL 中导出或向其中导入函数、数据和对象。 其中

dllexport 属性替换  __export 关键字。 dllimport 属性替换  extern 关键字。

export: 为了访问其他编译单元(如另一代码文件)中的变量或对象,对普通类型(包括基本数据类、结构和类),可以利用关键字extern,来使用这些变量或对象时; 此时,等价于标记为 declspec(dllexport),这意味着类模板将进行显式实例化,且必须定义类的成员。

dllexport 函数使用其修饰名称公开函数。 对于 C++ 函数,这包括名称重整。 对于 C 函数或声明为 extern "C" 的函数,这包括基于调用约定的平台特定修饰。 在这种情况下,将始终实例化并导出该函数,无论程序中是否有模块引用该函数。 假定该函数由另一个程序导入。

还可以定义为内联使用 dllimport 特性声明的函数。 在这种情况下,该函数可以展开(遵从 /Ob 规范),但决不实例化。 具体而言,如果采用内联导入函数的地址,则返回驻留在 DLL 中的函数地址。 此行为与采用非内联导入函数的地址相同。

这些规则适用于其定义出现在类定义中的内联函数。 此外,内联函数中的静态本地数据和字符串在 DLL 和客户端之间保持的标识与它们在单一程序(即,没有 DLL 接口的可执行文件)中保持的一样。

在提供导入的内联函数时谨慎操作。 例如,如果更新 DLL,请不要假定该客户端将使用更改后的 DLL 版本。 若要确保加载 DLL 的适当版本,请重新生成 DLL 的客户端。

结论

使用__declspec(dllimport) ,可以使得要导出的函数不再需要模块定义 ( .def) 文件,至少与导出函数的规范有关。而对于没有修饰的,可以通过使用模块定义 (.def) 文件进行链接,该文件在 EXPORTS 部分定义未修饰名。

参阅

dllexport、dllimport | Microsoft Docs 使用 dllexport 和 dllimport 定义内联 C++ 函数 | Microsoft Docs