一般规则和限制
Microsoft 专用
如果声明函数或对象,而无需 dllimport 或 dllexport 属性,函数或对象视为一部分的 DLL 接口。 因此,函数或对象的定义必须存在该模块或同一程序的另一个模块。 若要进行函数或对象部件 DLL 接口,必须声明函数或对象的定义在另一个模块作为 dllexport。 否则,链接器错误。
如果声明一功能或对象与 dllexport 属性,其定义必须出现在同一程序的某些模块。 否则,链接器错误。
如果在程序中的一个模块包含 dllimport 和 dllexport 声明相同功能的或对象, dllexport 属性优先于 dllimport 属性。 但是,编译器将生成警告。 例如:
__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
在 C++ 中,可以初始化一个全局声明或静态局部数据指针或处理数据对象的地址。 dllimport 属性,在 C. 的错误。 此外,还可以初始化函数的地址的静态本地函数指针声明 dllimport 属性。 在 C 中,这样分配设置指向 DLL 导入 thunk (代码存根的地址设置功能传输控件) 而不是函数的地址。 在 C++ 中,将设置为指向该函数的地址。 例如:
__declspec( dllimport ) void func1( void ); __declspec( dllimport ) int i; int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ void func2() { static int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ }
但是,因为,在对象的声明包括 dllexport 属性的过程必须对该对象提供了个定义是位于程序,可以初始化 dllexport 函数的地址的全局或局部静态函数指针。 同样,可以初始化 dllexport 数据对象的地址的全局或局部静态数据指针。 例如,下面的代码不会在 C 或 C++ 的错误:
__declspec( dllexport ) void func1( void ); __declspec( dllexport ) int i; int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay void func2() { static int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay }
由于在行为更改请在中引入 Visual C++ .NET 使应用程序 dllexport 一致的缓存类之间,类模板的专用化,因此,如果应用 dllexport 于具有基类不会被标记为 dllexport的规则类,编译器将生成 C4275。
,如果基类是类模板的专用化,编译器会生成同一个警告。 若要解决此问题,请标记基类与 dllexport。 类模板的专用化的问题是在何处放置 declspec(dllexport);不允许使用标记类模板。 相反,请显式实例化类模板并用 dllexport的此显式实例化。 例如:
template class __declspec(dllexport) B<int>; class __declspec(dllexport) D : public B<int> { // ...
,如果模板参数是派生的类,此解决方法失败。 例如:
class __declspec(dllexport) D : public B<D> { // ...
由于这与模板的常见模式,编译器更改了 dllexport 语义,以便在应用于具有一个或多个基类的类时,所以,当一个或多个基类是类模板的专用化时。 在这种情况下,编译器隐式应用 dllexport 于类模板的专用化。 在 Visual C++ .NET 中,用户可以执行而不是以下配置文件:
class __declspec(dllexport) D : public B<D> { // ...