共用方式為


編譯器警告 (層級 3) C4996

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

這很重要

此警告一律是來自宣告符號之標頭檔作者的刻意訊息。 不要在不了解後果的情況下使用已棄用的符號。

備註

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

/sdl (啟用其他安全性檢查) 編譯器選項會將此警告提升為錯誤。

關閉警告

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

關閉特定程式碼行的警告

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

關閉檔案中的警告

若要關閉檔案內後續所有內容的警告,請使用警告編譯指示。 #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 函數名稱

此項目的 POSIX 名稱已被取代。 請改用 ISO C 和 C++ 符合的名稱: new-name。 如需詳細資訊,請參閱線上說明。

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

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

若要關閉這些函式的淘汰警告,請定義前置處理器巨集 _CRT_NONSTDC_NO_WARNINGS。 您可以在指令行中定義此巨集,方法是包含選項 /D_CRT_NONSTDC_NO_WARNINGS

不安全的 CRT 程式庫函式

此函數或變數可能不安全。 請考慮改用 safe-version 。 若要停用淘汰,請使用 _CRT_SECURE_NO_WARNINGS。 如需詳細資訊,請參閱線上說明。

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

若要修正此問題,建議您改用函數或變數 safe-version 。 有時,出於可移植性或向後兼容性的原因,您不能。 請仔細確認程式碼中不會發生緩衝區覆寫或覆讀。 然後,您可以關閉警告。

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

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

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

不安全的標準程式庫函數

'std:: function_name ::_Unchecked_iterators::_Deprecate' 使用可能不安全的參數呼叫 std:: function_name - 此呼叫依賴呼叫端來檢查傳遞的值是否正確。 若要停用此警告,請使用 -D_SCL_SECURE_NO_WARNINGS。 請參閱如何使用 Visual C++ '檢查反覆專案」的檔

在 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 函數和變數

此函數或變數已被較新的程式庫或作業系統功能取代。 請考慮改用 new_item 。 如需詳細資訊,請參閱線上說明。

部分程式庫函數和廣域變數已棄用,因為已過時。 這些函數和變數可能會在程式庫的未來版本中刪除。 編譯器會針對這些項目發出淘汰警告,並建議偏好的替代方案。

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

若要關閉這些項目的淘汰警告,請定義 _CRT_OBSOLETE_NO_WARNINGS。 如需詳細資訊,請參閱已棄用函式或變數的檔。

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

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

此範例會產生 C4996,因為封送處理程式庫需要內容才能從 a System::String 轉換成 const 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
}