代码使用标记为 已弃用的函数、类成员、变量或 typedef。 使用 __declspec(deprecated) 修饰符或 C++14 [[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 中整个项目的警告,请执行以下操作:
打开项目的“属性页”对话框。 有关如何使用“属性页”对话框的信息,请参阅属性页。
选择 “配置属性>C/C++>Advanced 属性”页。
编辑“禁用特定警告”属性以添加
4996。 选择“确定”以应用更改。
使用预处理器宏禁用警告
还可以使用预处理器宏关闭库中使用的某些特定弃用警告类。 下面介绍了这些宏。
若要在 Visual Studio 中定义预处理器宏,请执行以下作:
打开项目的“属性页”对话框。 有关如何使用“属性页”对话框的信息,请参阅属性页。
展开 配置属性 > C/C++ > 预处理器。
在 预处理器定义 属性中,添加宏名称。 选择 “确定 ”保存,然后重新生成项目。
若要仅在特定源文件中定义宏,请在包含头文件的任何行之前添加一行 #define EXAMPLE_MACRO_NAME 。
下面是 C4996 警告和错误的一些常见来源:
POSIX 函数名称
此项目的 POSIX 名称已弃用。 请改用 ISO C 和C++一致性名称:
new-name。 有关详细信息,请参阅联机帮助。
Microsoft在 CRT 中重命名了一些 POSIX 和特定于 Microsoft 的库函数,以符合对保留和全局实现定义名称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需要类的两种marshal_context数据类型之间进行转换时,会发生此错误。 当封送库不支持转换时,还可以收到此错误。 有关封送库的详细信息,请参阅 C++中的封送处理概述。
此示例生成 C4996,因为封送处理库需要上下文从 a System::String 转换为 a 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
}