編譯器警告 (層級 3) C4996

您的程式碼會使用標示 已淘汰的函式、類別成員、變數或 typedef。 符號會使用 __declspec(deprecated) 修飾詞或 C++14 [[deprecated]] 屬性來取代。 實際的 C4996 警告訊息是由 deprecated 宣告的修飾詞或屬性所指定。

重要

這個警告一律是宣告符號之標頭檔作者的刻意訊息。 請勿在不了解後果的情況下,使用已被取代的符號。

備註

Visual Studio 程式庫中的許多函式、成員函式、函式範本和全域變數都 已被取代 。 有些函式,例如 POSIX 和 Microsoft 特定函式,現在已被取代,因為它們現在有不同的慣用名稱。 某些 C 執行時間程式庫函式已被取代,因為它們不安全且具有更安全的變體。 其他專案已被取代,因為它們已經過時。 取代訊息通常包含已取代函式或全域變數的建議取代專案。

[啟用其他安全性檢查] 編譯器選項會將 /sdl 這個警告提升為錯誤。

關閉警告

若要修正 C4996 問題,我們通常建議您變更程式碼。 請改用建議的函式和全域變數。 如果您需要基於可攜性的原因使用現有的函式或變數,您可以關閉警告。

關閉特定程式程式碼的警告

若要關閉特定程式程式碼的警告,請使用 warning pragma、 #pragma warning(suppress : 4996)

關閉檔案內的警告

若要關閉檔案中後續所有專案的警告,請使用警告 pragma, #pragma warning(disable : 4996)

關閉命令列組建中的警告

若要在命令列組建中全域關閉警告,請使用 /wd4996 命令列選項。

關閉 Visual Studio 中專案的警告

若要關閉 Visual Studio IDE 中整個專案的警告:

  1. 開啟專案的 [ 屬性頁] 對話方塊。 如需如何使用 [屬性頁] 對話方塊的資訊,請參閱 屬性頁

  2. 選取 [ 組態屬性 > C/C++ > 進階 ] 屬性頁。

  3. 編輯停用 特定警告 屬性以新增 4996 。 選擇 [ 確定 ] 以套用變更。

使用預處理器宏停用警告

您也可以使用預處理器宏來關閉程式庫中所使用的特定取代警告類別。 這些宏如下所述。

若要在 Visual Studio 中定義預處理器宏:

  1. 開啟專案的 [ 屬性頁] 對話方塊。 如需如何使用 [屬性頁] 對話方塊的資訊,請參閱 屬性頁

  2. 展開 [組態屬性 > C/C++ > 預處理器 ]。

  3. 在預處理器定義 屬性中 ,新增宏名稱。 選擇 [確定] 加以儲存,然後重建您的專案。

若要只在特定的原始程式檔中定義宏,請在包含標頭檔的任何一行之前新增一行,例如 #define EXAMPLE_MACRO_NAME

以下是 C4996 警告和錯誤的一些常見來源:

POSIX 函式名稱

The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: new-name. See online help for details.

Microsoft 在 CRT 中重新命名了一些 POSIX 和 Microsoft 特定程式庫函式,以符合保留和全域實作定義名稱上的 C99 和 C++03 條件約束。 只有名稱已被取代,而不是函式本身 。 在大部分情況下,會將前置底線新增至函式名稱,以建立一致的名稱。 編譯器會發出原始函式名稱的取代警告,並建議慣用的名稱。

若要修正此問題,我們通常建議您變更程式碼以改用建議的函式名稱。 不過,更新的名稱是 Microsoft 特定的。 如果您需要基於可攜性的原因使用現有的函式名稱,您可以關閉這些警告。 函式仍可在程式庫中以其原始名稱提供。

若要關閉這些函式的淘汰警告,請定義預處理器宏 _CRT_NONSTDC_NO_WARNINGS 。 您可以在命令列定義這個宏,方法是包含 選項 /D_CRT_NONSTDC_NO_WARNINGS

不安全的 CRT 程式庫函式

This function or variable may be unsafe. Consider using safe-version instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

Microsoft 已淘汰某些 CRT 和 C++ 標準程式庫函式和全域,因為有更安全的版本可供使用。 大部分已被取代的函式都允許對緩衝區進行未核取的讀取或寫入存取。 其誤用可能會導致嚴重的安全性問題。 編譯器會為這些函式發出已被取代的警告,並建議所應使用的函式。

若要修正此問題,建議您改用 函式或變數 safe-version 。 有時候,基於可攜性或回溯相容性的原因,您無法。 請仔細確認緩衝區覆寫或過度讀取在您的程式碼中不可能發生。 然後,您可以關閉警告。

若要關閉 CRT 中這些函式的淘汰警告,請定義 _CRT_SECURE_NO_WARNINGS

若要關閉已淘汰全域變數的相關警告,請定義 _CRT_SECURE_NO_WARNINGS_GLOBALS

如需這些已被取代函式和全域的詳細資訊,請參閱 CRT 保管庫程式庫中的安全性功能:C++ 標準程式庫

不安全的標準程式庫函式

'std:: function_name ::_Unchecked_iterators::_Deprecate' Call to std:: function_name with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'

在 Visual Studio 2015 中,此警告會出現在偵錯組建中,因為某些 C++ 標準程式庫函式範本不會檢查參數的正確性。 通常是因為函式沒有足夠的資訊來檢查容器界限。 或者,因為反覆運算器可能未正確地搭配 函式使用。 此警告可協助您識別這些函式,因為它們可能是程式中嚴重安全性漏洞的來源。 如需詳細資訊,請參閱 已檢查的反覆運算器

例如,如果您將元素指標傳遞至 std::copy ,而不是純陣列,則此警告會出現在偵錯模式中。 若要修正此問題,請使用適當宣告的陣列,讓程式庫可以檢查陣列範圍並執行界限檢查。

// C4996_copyarray.cpp
// compile with: cl /c /W4 /D_DEBUG C4996_copyarray.cpp
#include <algorithm>

void example(char const * const src) {
    char dest[1234];
    char * pdest3 = dest + 3;
    std::copy(src, src + 42, pdest3); // C4996
    std::copy(src, src + 42, dest);   // OK, copy can tell that dest is 1234 elements
}

數個標準程式庫演算法已更新為在 C++14 中具有「雙重範圍」版本。 如果您使用雙重範圍版本,第二個範圍會提供必要的界限檢查:

// C4996_containers.cpp
// compile with: cl /c /W4 /D_DEBUG C4996_containers.cpp
#include <algorithm>

bool example(
    char const * const left,
    const size_t leftSize,
    char const * const right,
    const size_t rightSize)
{
    bool result = false;
    result = std::equal(left, left + leftSize, right); // C4996
    // To fix, try this form instead:
    // result = std::equal(left, left + leftSize, right, right + rightSize); // OK
    return result;
}

此範例示範數種更多方式,標準程式庫可用來檢查反覆運算器使用方式,以及未核取的使用方式可能很危險:

// C4996_standard.cpp
// compile with: cl /EHsc /W4 /MDd C4996_standard.cpp
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <numeric>
#include <string>
#include <vector>

using namespace std;

template <typename C> void print(const string& s, const C& c) {
    cout << s;

    for (const auto& e : c) {
        cout << e << " ";
    }

    cout << endl;
}

int main()
{
    vector<int> v(16);
    iota(v.begin(), v.end(), 0);
    print("v: ", v);

    // OK: vector::iterator is checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    vector<int> v2(16);
    transform(v.begin(), v.end(), v2.begin(), [](int n) { return n * 2; });
    print("v2: ", v2);

    // OK: back_insert_iterator is marked as checked in debug mode
    // (i.e. an overrun is impossible)
    vector<int> v3;
    transform(v.begin(), v.end(), back_inserter(v3), [](int n) { return n * 3; });
    print("v3: ", v3);

    // OK: array::iterator is checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    array<int, 16> a4;
    transform(v.begin(), v.end(), a4.begin(), [](int n) { return n * 4; });
    print("a4: ", a4);

    // OK: Raw arrays are checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    // NOTE: This applies only when raw arrays are
    // given to C++ Standard Library algorithms!
    int a5[16];
    transform(v.begin(), v.end(), a5, [](int n) { return n * 5; });
    print("a5: ", a5);

    // WARNING C4996: Pointers cannot be checked in debug mode
    // (i.e. an overrun triggers undefined behavior)
    int a6[16];
    int * p6 = a6;
    transform(v.begin(), v.end(), p6, [](int n) { return n * 6; });
    print("a6: ", a6);

    // OK: stdext::checked_array_iterator is checked in debug mode
    // (i.e. an overrun triggers a debug assertion)
    int a7[16];
    int * p7 = a7;
    transform(v.begin(), v.end(),
        stdext::make_checked_array_iterator(p7, 16),
        [](int n) { return n * 7; });
    print("a7: ", a7);

    // WARNING SILENCED: stdext::unchecked_array_iterator
    // is marked as checked in debug mode, but it performs no checking,
    // so an overrun triggers undefined behavior
    int a8[16];
    int * p8 = a8;
    transform( v.begin(), v.end(),
        stdext::make_unchecked_array_iterator(p8),
        [](int n) { return n * 8; });
    print("a8: ", a8);
}

如果您已確認程式碼無法發生緩衝區滿溢錯誤,您可以關閉此警告。 若要關閉這些函式的警告,請定義 _SCL_SECURE_NO_WARNINGS

已啟用檢查的反覆運算器

如果您未在定義為 1 或 2 時 _ITERATOR_DEBUG_LEVEL 使用已檢查的反覆運算器,也會發生 C4996。 根據預設,偵錯模式組建的 設定為 2,零售組建則設定為 0。 如需詳細資訊,請參閱 已檢查的反覆運算器

// C4996_checked.cpp
// compile with: /EHsc /W4 /MDd C4996_checked.cpp
#define _ITERATOR_DEBUG_LEVEL 2

#include <algorithm>
#include <iterator>

using namespace std;
using namespace stdext;

int main() {
    int a[] = { 1, 2, 3 };
    int b[] = { 10, 11, 12 };
    copy(a, a + 3, b + 1);   // C4996
    // try the following line instead:
    // copy(a, a + 3, checked_array_iterator<int *>(b, 3));   // OK
}

不安全的 MFC 或 ATL 程式碼

如果您使用因安全性原因而淘汰的 MFC 或 ATL 函式,可能會發生 C4996。

若要修正此問題,強烈建議您變更程式碼以改用更新的函式。

如需有關如何隱藏這些警告的資訊,請參閱 _AFX_SECURE_NO_WARNINGS

過時的 CRT 函式和變數

This function or variable has been superseded by newer library or operating system functionality. Consider using new_item instead. See online help for details.

某些程式庫函式與全域變數因為過時而被取代。 這些函式及變數可能會從後續版本的程式庫中移除。 編譯器會為這些函式發出已被取代的警告,並建議所應使用的函式。

若要修正此問題,建議您變更程式碼以使用建議的函式或變數。

若要關閉這些專案的淘汰警告,請定義 _CRT_OBSOLETE_NO_WARNINGS 。 如需詳細資訊,請參閱文件中所列之已被取代的函式或變數。

CLR 程式碼中的封送處理錯誤

當您使用 CLR 封送處理程式庫時,也會發生 C4996。 在此情況下,C4996 是錯誤,而不是警告。 當您使用 marshal_as 來轉換需要 Class 的兩種 marshal_context 資料類型時,就會發生此錯誤。 當封送處理程式庫不支援轉換時,您也可以收到此錯誤。 如需封送處理程式庫的詳細資訊,請參閱 C++ 封送處理概觀。

此範例會產生 C4996,因為封送處理程式庫需要內容從 System::Stringconst char * 轉換成 。

// C4996_Marshal.cpp
// compile with: /clr
// C4996 expected
#include <stdlib.h>
#include <string.h>
#include <msclr\marshal.h>

using namespace System;
using namespace msclr::interop;

int main() {
   String^ message = gcnew String("Test String to Marshal");
   const char* result;
   result = marshal_as<const char*>( message );
   return 0;
}

範例:使用者定義已被取代的函式

當您不再建議使用 deprecated 特定函式時,您可以在自己的程式碼中使用 屬性來警告呼叫端。 在此範例中,C4996 會在兩個位置產生:一個用於宣告已被取代函式的行,另一個用於使用函式的行。

// C4996.cpp
// compile with: /W3
// C4996 warning expected
#include <stdio.h>

// #pragma warning(disable : 4996)
void func1(void) {
   printf_s("\nIn func1");
}

[[deprecated]]
void func1(int) {
   printf_s("\nIn func2");
}

int main() {
   func1();
   func1(1);    // C4996
}