如何摆脱Visual Studio(strcpy,sprintf,strdup)中的“不安全”警告/错误

我试图摆脱一些编译器警告说,strcpy,sprintf等是不安全的。 我得到了为什么他们不安全,但我想不出一种以C ++风格修复代码的好方法。

下面是代码的摘录:

extList->names[i]=(char *)malloc(length*sizeof(char)); strcpy(extList->names[i],extName); // unsafe // strncpy(extList->names[i],extName,length); // also unsafe 

这里是消息:

C4996:'strcpy':这个函数或variables可能是不安全的。 考虑使用strcpy_s来代替。 要禁用弃用,请使用_CRT_SECURE_NO_WARNINGS。 详细信息请参见在线帮助。

我不能想到一个安全的方式来复制C ++中的数据,而不知道要复制的东西的长度。 我知道有strlen(),但这也是不安全的,因为它假定(也许不正确),数据是空终止的。

也:

 // used to concatenate: sprintf(extStr,"%s%s",platExtStr,glExtStr); 

C4996:'sprintf':这个函数或variables可能是不安全的。 考虑使用sprintf_s代替。 要禁用弃用,请使用_CRT_SECURE_NO_WARNINGS。 详细信息请参见在线帮助。

使用std :: string来连接很容易,但是我需要以某种方式将数据转换为extStr(而不是使用strcpy,lol)。 string :: c_str()函数返回一个指向不可修改的数据的指针,所以我不能把extStr设置为等于它。 (而且我甚至不确定c_str()指针是否需要稍后调用它的delete?是否使用“new”分配空间?)

有关这个东西的任何意见? 这是一个不是我的10,000行文件的一部分…所以我不是热衷于重写C ++方式的东西。

Solutions Collecting From Web of "如何摆脱Visual Studio(strcpy,sprintf,strdup)中的“不安全”警告/错误"

您并不需要编译指令来禁用它们。

对于win32 / msvc,在ProjectProperties – >配置属性 – > C / C ++ – >预处理器 – >预处理器定义中,添加以下宏:

 _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_DEPRECATE 

或者你可以通过命令行参数传递thos(-D_CRT_SECURE_NO_DEPRECATE)。 你可能可以在某些* .cpp文件的开头#define它们。 另外,有可能更多(见crtdefs.h – 看起来像有很多…)。 这些警告通常告诉你,哪些宏可以禁用它们 – 只要读取编译器输出即可。

这是对这个问题的另一个答案。

 #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4996) #endif strcpy(destination, source); #ifdef _MSC_VER #pragma warning(pop) #endif 

如果摆脱警告只是你的目标…简单地定义这个_CRT_SECURE_NO_WARNINGS ,它会压制所有的弃用警告。 但是这并不能解决不安全的CRT功能的根本问题。

如果您在Visual Studio版本> = 2005,并且想要以适当的方式解决这些警告…最简单的方法是#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1在您的项目。

没有任何进一步的代码更改,你可以观察到大多数的警告是自动修复的。 通过定义这个窗口会自动调用大多数不安全的CRT函数的安全重载函数。 自动计算静态数组的缓冲区大小。

虽然动态分配的缓冲区不是这样固定的,我们需要手动修复它们。 请参阅此链接进一步的细节。

以下是以编程方式更正您的示例的一种方法

 strcpy_s(extList->names[i], length, extName); 

你知道要复制多少 – 你为它分配了空间!

当然,你不会愿意复制超过你分配的空间吗?

我宁愿使用通过限制复制项目的数量来明确避免缓冲区溢出的方法。 当我还是我们使用的C程序员时

 dest = malloc(len); // note: where did we get len? if ( dest is null ) panic! // note: malloc can fail strncpy(dest, src, len); dest[len-1] =0; 

这有些混乱,并且已经指出使用strncpy()这个方法确实是最初为固定宽度的字段而不是字符串设计的。 但是它确实如此

有一些方法,如strdup()和strlcpy(),我们可以帮助。

我的建议是:

1)。 你的目标不应该是压制警告,而是使代码健壮。

2)。 复制字符串时,您需要确保这些事情:

  • 保护自己免受不良的输入,例如一个未终止或过长的字符串。
  • 保护你自己的malloc失败,
  • 强烈希望计数的字符数量的副本复制,直到我们看到空
  • 如果你声称建立一个字符串,然后确定你null终止它

如果strlcpy()在你的环境中可用,那么你可以使用它,否则为什么不写你自己的小实用功能? 那么如果在那个函数中有警告,那么你就已经本地化了。

在你的第一个例子中,你已经知道了长度。 由于你没有分配length+1字节,我会假设length包括空终止符。 在这种情况下,只需std::copy字符串: std::copy(extName, extName + length, expList->names[i]);

在你的第二个例子中,假设源字符串是空的终止,你可以计算目标字符串的长度,并再次使用std::copy手动连接,或者你可以使用std::string和从c_str的结果中的std::copy到你的目的地(再次假设你分配了足够的空间)。

c_str()不分配需要外部删除的内存。

最后要注意的是sizeof(char)将始终是一个,所以在malloc中是多余的,尽管该字符中的位数可能不是8(见CHAR_BIT )。

我认为你应该尽可能地替换所有的函数调用来调用你自己的实现。 一个很好的例子就是替换strcpy并在其中调用特定于编译器的版本的strcpy。 您的实现可以很容易地修改,以适应您选择的任何编译器,特别是如果您将添加或更改平台/编译器。

例:

 char* StringCopy(char* Destination, const char* Source, size_t DestinationSize) { #ifdef _MSC_VER return strcpy_s(Destination, Source, DestinationSize); #else if(!(strlen(Source) >= DestinationSize)) return strcpy(Destination, Source); else return 0x0; #endif } 

如果可移植性不是问题,则可以使用“strcpy_s” 。

如果这个代码只是针对Windows平台编译的,那么最好使用这些函数的安全版本。 但是,如果这个代码要跨多个平台(linux,Aix等)编译,那么你可以通过使用_CRT_SECURE_NO_WARNINGS来禁用你的windows项目配置文件(例如.vcxproj)中的警告,或者你可以使用一个代码片段这个函数在.cpp文件中被调用的地方。

 #if _OS_ == _OS__WINDOWS //secure function call #else //already written code #endif