Share via


編譯器警告 (層級 2) C4412

' function' : 函式 簽章包含類型 ' type ';C++ 物件在純程式碼與混合或原生之間傳遞不安全。

備註

Visual Studio 2015 中已淘汰 /clr:pure 編譯器選項,Visual Studio 2017 不支援。 如果您有需要純潔的程式碼,建議您將其移植到 C#。

編譯器偵測到可能導致執行時間錯誤的可能不安全狀況:呼叫是從 /clr:pure 編譯和匯入至透過 dllimport 匯入的函式,而函式簽章包含不安全的類型。 如果類型包含成員函式,或具有不安全型別的資料成員或不安全型別的間接性,則類型是不安全的。

這是不安全的,因為純和原生程式碼之間預設呼叫慣例的差異(或混合原生和管理)。 將函式匯入 / 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
}

下列範例是宣告兩種型別的標頭檔。 型 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
}