我在VS2010中编写代码,我碰巧在编译后看到编译器为strcpy和sprintf调用提供了C4996警告(“此函数或变量可能不安全”)。
但是,我无法获得memcpy的类似警告(并且可能在代码中有更多类似的'不安全'函数调用)
int _tmain(int argc, _TCHAR* argv[])
{
char buf1[100], buf2[100];
strcpy (buf1, buf2); // Warning C4996 displayed here asking to use strcpy_s instead
memcpy (buf1, buf2, 100); // No warning here asking to use memcpy_s
memcpy_s(buf1, 100, buf2, 100);
return 0;
}
为什么会这样?如何在我的代码中为所有可能的不安全呼叫打开C4996警告?
答案 0 :(得分:17)
通常,要编译C代码,您需要一个符合C的编译器。 Visual Studio是一个不合格的C ++编译器。
您收到警告,因为Visual Studio很糟糕。 See this。
只要您使用Microsoft认为过时的功能,就会出现C4996。显然,微软决定他们应该决定C语言的未来,而不是ISO C工作组。因此,您会得到错误的警告以获得完美的代码。编译器就是问题所在。
strcpy()函数没有任何问题,这是一个神话。这个功能已经存在了大约30 - 40年,每一点都有适当的记录。因此,即使对于初学者C程序员来说,该功能的功能和功能也不应该让人感到意外。
strcpy做什么和不做什么:
由于上面的最后一句话,在调用strcpy之前必须知道以下内容:
\0
结尾的数据,则调用者应用程序中存在错误。例如,在您发布的代码中,您从未初始化数组,因此您的程序可能会崩溃并烧毁。这个bug与strcpy()函数没有丝毫相关,也不会通过替换strcpy()来解决。
答案 1 :(得分:6)
strcpy
,则 NUL
不安全,因为它可能会复制比目标区域更多的字符。使用memcpy
,复制的字节数是固定的。
memcpy_s
函数实际上让程序员更容易做错 - 你传递了两个长度,它使用两者中较小的一个,你得到的只是一个错误代码,可以默默地忽略努力。调用memcpy
需要填写size
参数,这应该让程序员考虑要传递的内容。
答案 2 :(得分:1)
您收到这些警告是因为没有传递字符串的长度并依赖\0
终止是不安全的,因为它们可能导致缓冲区溢出。在memcpy中你传递长度所以没有溢出问题。
您可以使用类似
的内容#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4996)
#endif
strcpy... ; // Code that causes unsafe warning
#ifdef _MSC_VER
# pragma warning(pop)
#endif
如果您不担心可移植性,可以使用strcpy_s
等替代方法
答案 3 :(得分:1)
包含在标题"stdafx.h"
定义
#define _CRT_SECURE_NO_WARNINGS
至于strcpy
和memcpy
的差异,那么最后一个函数有第三个参数,它明确指定必须复制多少个字符。第一个函数没有信息将从源字符串复制到目标字符串的字符数,因此通常情况下,可能会覆盖为目标字符串分配的内存。
答案 4 :(得分:0)
因为strcpy
和sprintf
确实是不安全的函数,所以它取决于字符串的内容不会溢出。相反,您应该使用strncpy
和snprintf
来确保它不会覆盖内存。
虽然memcpy
不是这种情况,但它具有长度,因此只要长度正确,它就不会覆盖内存。
答案 5 :(得分:0)
该警告表示该函数已弃用且在将来的版本中不可用:http://msdn.microsoft.com/en-US/en-en/library/ttcz0bys.aspx您无法将其他函数添加到Microsoft的弃用列表中。
弃用的原因是“不安全”,但这与您的假设“C4496向您显示所有不安全的功能”不同。
答案 6 :(得分:0)
您在sprintf
和strcpy
而不是memcpy
上收到警告的原因是因为memcpy
的长度参数限制了您复制的内存量。对于strcpy
和memcpy
,输入必须以\0
终止。如果没有,它将继续超出范围。您可以使用snprintf
和strncpy
函数来限制此操作。那些可以隐含地限制可以复制多少。
请注意,Microsoft已弃用snprintf
,因此您应该使用替换函数_snprintf
。但是,这是MSVC特定的功能。
我建议一起取消char *
个缓冲区并使用stl容器切换到C ++,例如std::string
。这些将为您节省大量的调试麻烦并保持代码的可移植性。