編譯器警告 (層級 3) C4996
您的程式碼有使用標示為已被取代 (deprecated) 的函式、類別成員、變數或 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 整個專案的警告:
開啟專案的 [屬性頁] 對話。 如需如何使用 [屬性頁] 對話框的資訊,請參閱屬性頁 (部分機器翻譯)。
選取 [設定屬性]>[C/C++]>[進階] 屬性頁面。
編輯 [停用特定警告] 屬性以新增
4996
。 選擇 [確定] 以套用變更。
使用前置處理器巨集停用警告
您也可以使用前置處理器巨集來關閉程式庫中所使用的特定已取代警告類別。 這些巨集如下所述。
若要在 Visual Studio 中定義前置處理器巨集:
開啟專案的 [屬性頁] 對話。 如需如何使用 [屬性頁] 對話框的資訊,請參閱屬性頁 (部分機器翻譯)。
展開 [組態屬性] > [C/C++] > [前置處理器]。
在 [前置處理器定義] 屬性中新增巨集名稱。 選擇 [確定] 加以儲存,然後重建您的專案。
若要只在特定的來源檔案中定義此巨集,請在包含標頭檔的該行前加入類似 #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
。
已啟用檢查的迭代器
如果您未在 _ITERATOR_DEBUG_LEVEL
定義為 1 或 2 時使用已檢查的迭代器,也會發生 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
轉換兩種需要 marshal_context
類別 (部分機器翻譯) 的資料類型時,便會發生此錯誤。 當封送處理程式庫不支援某項轉換時,也會收到這個錯誤。 如需封送處理程式庫的詳細資訊,請參閱 C++/CLI 中的封送處理概觀 (部分機器翻譯)。
此範例會產生 C4996 錯誤,因為封送處理程式庫需要內容,才能從 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
}