コンパイラの警告 (レベル 2) C4412

'function' : 関数のシグネチャが型 'type' を含んでいます。C++ オブジェクトを、純粋なコードと混合またはネイティブ コードとの間で渡すことは安全ではありません。

解説

/clr:pure コンパイラ オプションは Visual Studio 2015 では非推奨とされており、Visual Studio 2017 ではサポートされていません。 純粋である必要があるコードがある場合は、C# に移植することをお勧めします。

実行時エラーを引き起こす可能性がある、潜在的に安全でない状況がコンパイラによって検出されました。dllimport によってインポートされた関数が /clr:pure コンパイル単位から呼び出され、安全でない型が関数シグネチャに含まれています。 型にメンバー関数が含まれているか、安全でない型のデータ メンバーまたは安全でない型への間接参照が型に存在している場合、その型は安全ではありません。

純粋なコードとネイティブ コード (またはネイティブとマネージドの混在) では既定の呼び出し規則が異なるため、これは安全ではありません。 (dllimport を介して) 関数を /clr:pure コンパイル単位にインポートするときは、シグネチャでの各型の宣言が、関数をエクスポートするコンパイル単位での宣言と同じであることを確認してください (暗黙的な呼び出し規則の違いには特に注意してください)。

仮想メンバー関数は特に、予期しない結果につながる傾向があります。 ただし、非仮想関数であっても、テストして、正しい結果が得られるのを確認することをお勧めします。 正しい結果が得られることを確認できたら、この警告は無視してもかまいません。

C4412 は、既定では無効になっています。 詳細については、「既定で無効になっているコンパイラ警告」および「dllexport、dllimport」を参照してください。

この警告を解決するには、型からすべての関数を削除します。

次の例では C4412 が生成されます。

// C4412.cpp
// compile with: /c /W2 /clr:pure
#pragma warning (default : 4412)

struct Unsafe {
   virtual void __cdecl Test();
};

struct Safe {
   int i;
};

__declspec(dllimport) Unsafe * __cdecl func();
__declspec(dllimport) Safe * __cdecl func2();

int main() {
   Unsafe *pUnsafe = func();   // C4412
   // pUnsafe->Test();

   Safe *pSafe = func2();   // OK
}

次の例は、2 つの型を宣言するヘッダー ファイルです。 Unsafe 型にはメンバー関数が存在するため、この型は安全ではありません。

// C4412.h
struct Unsafe {
   // will be __clrcall if #included in pure compilation
   // defaults to __cdecl in native or mixed mode compilation
   virtual void Test(int * pi);

   // try the following line instead
   // virtual void __cdecl Test(int * pi);
};

struct Safe {
   int i;
};

この例では、ヘッダー ファイルで定義されている型を使用して関数をエクスポートします。

// C4412_2.cpp
// compile with: /LD
#include "C4412.h"

void Unsafe::Test(int * pi) {
   *pi++;
}

__declspec(dllexport) Unsafe * __cdecl func() { return new Unsafe; }
__declspec(dllexport) Safe * __cdecl func2() { return new Safe; }

/clr:pure コンパイル単位での既定の呼び出し規則は、ネイティブ コンパイルとは異なります。 C4412.h がインクルードされる場合、Test は既定で __clrcall になります。 (/c を使用せずに) このプログラムをコンパイルして実行すると、プログラムは例外をスローします。

次の例では C4412 が生成されます。

// C4412_3.cpp
// compile with: /W2 /clr:pure /c /link C4412_2.lib
#pragma warning (default : 4412)
#include "C4412.h"

__declspec(dllimport) Unsafe * __cdecl func();
__declspec(dllimport) Safe * __cdecl func2();

int main() {
   int n = 7;
   Unsafe *pUnsafe = func();   // C4412
   pUnsafe->Test(&n);

   Safe *pSafe = func2();   // OK
}