我正在编写一些预期在多个编译器上编译的C代码(至少在MSVC
和GCC
上)。由于我是C语言的初学者,因此我打开了所有警告并将警告视为错误(GCC中的-Werror
和MSVC中的/WX
),以防止我犯下愚蠢的错误。
当我编译一些在MSVC上使用strcpy
的代码时,我收到警告,如
warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
strcpy
包裹起来,
my_strcpy()
{
#ifdef WIN32
// use strcpy_s
#ELSE
// use strcpy
}
有什么想法吗?
答案 0 :(得分:4)
关于此主题,有很多很多关于SO的讨论。我敢肯定,像strncpy,strlcpy等常见的嫌疑人会再次出现在这里。只需在搜索框中输入“strcpy”,然后阅读一些较长的线程即可获得概述。
我的建议是:无论您的最终选择是什么,最好遵循DRY原则并继续按照my_strcpy()的示例进行操作。不要在您的代码中抛出原始调用,使用包装器并将它们集中在您自己的字符串处理库中。如果您稍后改变主意,这将减少整体代码(样板文件),并且您有一个中心位置可以进行修改。
当然这会打开一些其他的蠕虫病毒,特别是初学者:内存处理责任和界面设计。这个主题本身和5个人都会给你10个如何做的建议。中央库通常具有很好的效果,它会强制执行一个决策,您将在整个代码库中执行该决策,而不是使用模块A中的方法a和模块B中的方法b,当您尝试将A与B连接时会导致麻烦。 ..
答案 1 :(得分:4)
每当你在非恒定大小的缓冲区之间移动数据时,你必须(喘气!omg!)实际思考它是否适合。使用声称“安全”的函数(如MS特定的strcpy_s
或BSD strlcpy
)将保护您免受某些明显的缓冲区溢出条件的影响,但不会保护您免受字符串截断导致的错误。在计算必要的缓冲区大小时,它也不会保护您免受整数溢出的影响。
除非你是处理C字符串的专家,否则我建议忘记特殊功能并评论代码的每个行,这些代码将执行可变长度/位置写入,并证明你是如何理由的知道,在程序的这一点上,你将要使用的长度/偏移量在缓冲区大小的范围内。对你对大小/偏移量进行算术运算的行也这样做 - 记录你如何知道算术不会溢出,如果你发现你不知道就加上溢出测试。
另一种方法是将所有字符串处理完全包装在一个字符串对象中,该字符串对象存储缓冲区的长度以及字符串,并在需要放大字符串时自动重新分配,然后仅使用const char *
进行读取 - 当您需要将字符串传递给系统函数或其他库时,只能访问字符串。这将牺牲你期望从C中获得的一些性能,但它将帮助你确保你不犯错误。只是不要把它带到极端。您无需在字符串包装器中复制strchr
,strstr
等内容。只需提供复制字符串对象,连接它们并截断它们的方法,然后使用在const char *
上运行的现有库函数,您可以执行任何您想要的操作。
答案 2 :(得分:1)
我倾向于使用更安全的函数snprintf
†,它可以在两个平台上使用,而不是根据平台具有不同的路径。您需要使用define来阻止MSVC上的警告。
†虽然可能稍微不那么安全 - 它会返回一个字符串,该字符串在出错时不会以nul结尾,因此您必须检查返回,但不会导致缓冲区溢出。