一般的な規則と制約
Microsoft 固有の仕様
dllimport
属性またはdllexport
属性を指定しないで関数やオブジェクトを宣言した場合、その関数やオブジェクトは DLL インターフェイスの一部とは見なされません。 したがって、関数またはオブジェクトの定義は、該当のモジュール内か、同じプログラムの別のモジュール内に存在している必要があります。 関数やオブジェクトを DLL インターフェイスに含める場合は、その関数またはオブジェクトの定義を他のモジュールでdllexport
として宣言する必要があります。 定義しない場合は、リンカー エラーが生成されます。dllexport
属性を使用して関数やオブジェクトを宣言する場合、その定義は同じプログラムのどこかのモジュールに存在する必要があります。 定義しない場合は、リンカー エラーが生成されます。プログラムの 1 つのモジュールに、同じ関数またはオブジェクトの
dllimport
宣言とdllexport
宣言の両方が含まれる場合は、dllexport
属性がdllimport
属性よりも優先されます。 ただし、コンパイラの警告が生成されます。 次に例を示します。__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
C++ では、グローバルに宣言されたローカル データ ポインターまたは静的ローカル データ ポインター、または
dllimport
属性で宣言されたデータ オブジェクトのアドレスを使用して初期化できます。この場合、C でエラーが発生します。さらに、dllimport
属性で宣言された関数のアドレスを使用して、静的ローカル関数ポインターを初期化できます。 C では、このような代入で、関数のアドレスではなく、DLL インポート サンク (関数に制御を移すコード スタブ) のアドレスがポインターに設定されます。 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 }
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> { // ...
テンプレートではこれが一般的なパターンであるため、コンパイラでは、1 つ以上の基底クラスを持つクラスに
dllexport
が適用され、その基底クラスの 1 つ以上がクラス テンプレートの特殊化である場合の dllexport のセマンティックが変更されました。 このような場合、コンパイラはクラス テンプレートの特殊化に暗黙的にdllexport
を適用します。 次の操作を行い、警告は表示されない場合があります。class __declspec(dllexport) D : public B<D> { // ...
Microsoft 固有の仕様はここまで
関連項目
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示