編譯器警告 (層級 3) C4996

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

重要

這項警告一律是來自宣告符號的標頭檔作者所刻意提出的訊息。 請勿在不了解結果的情況下使用已被取代的符號。

備註

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

關閉警告

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

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

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

關閉檔案內的警告

若要針對接下來的所有專案關閉檔案中的警告,請使用 warning pragma #pragma warning(disable : 4996)

關閉命令列組建中的警告

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

關閉 Visual Studio 中專案的警告

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

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

  2. 選取 [設定屬性>C/c + +>Advanced ] 屬性頁。

  3. 編輯 [ 停用特定警告 ] 屬性以加入 4996 。 選擇 [確定] 以套用您的變更。

使用預處理器宏停用警告

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

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

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

  2. 展開 Configuration Properties > 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 來定義此宏。

Unsafe 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 + + 標準程式庫函式和 globals,因為有更安全的版本可供使用。 大部分被取代的函式允許對緩衝區進行未檢查的讀取或寫入存取。 誤用可能會導致嚴重的安全性問題。 編譯器會為這些函式發出已被取代的警告,並建議所應使用的函式。

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

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

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

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

Unsafe 標準程式庫函數

'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 ,而不是單純的陣列,則這個警告會出現在 [Debug] 模式中。 若要修正此問題,請使用適當宣告的陣列,讓程式庫可以檢查陣列範圍並執行界限檢查。

// 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。 針對 debug 模式組建,預設會設定為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
}

Unsafe 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 來轉換需要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
}