如何将当前的 strcpy 转换为 strcpy_s?
Posted
技术标签:
【中文标题】如何将当前的 strcpy 转换为 strcpy_s?【英文标题】:How to convert current strcpy to strcpy_s? 【发布时间】:2017-10-01 01:25:35 【问题描述】:我有一个大型项目,到处都在使用strcpy
。我正在考虑使用strcpy_s
而不是strcpy
。我想我已经使用了将近 10,000 次 strcpy
。每次strcpy
换一个都太麻烦了。有什么有效的转化方式吗?
【问题讨论】:
你的意思是除了显而易见的? (即全局 s&r,然后修复所有损坏的东西)。根据定义,每个损坏的地方都需要检查,所以分支你的代码,看看它有多糟糕。strcpy_s()
无论如何都是毫无意义的。
由于dest
的大小可以在任何地方声明,自动执行任何操作似乎都非常困难。
一万次!为什么这被标记为 C++?
考虑n1967,它建议“......附件 K 要么从 C 标准的下一个修订版中删除,要么弃用然后删除。”确定要将代码切换到strcpy_s()
?建议阅读“常见错误”部分,了解您遇到的问题。
【参考方案1】:
你真的不应该在没有检查的情况下这样做,因为如果没有明智地完成缓冲区管理,就会失去加强缓冲区管理的意义。
由于目标缓冲区的性质(例如静态或堆分配)对于strcpy_s()
的正确参数非常重要,而现有的strcpy()
调用中当然不存在该信息,您必须以任何方式添加它。这需要一个人。
通常像strcpy(dest, src);
这样的调用可以转换为strcpy_s(dest, sizeof dest, src);
,但是如果dest
是堆分配的,那么这将只是指针的大小而不是指向缓冲区的大小,这当然是错误的。
【讨论】:
你必须确保dest
被声明为一个数组!因为如果dest
是指针,这通常是一场代码破坏灾难。
为了进一步增加混淆,至少有一个 C++ 供应商 (MS) 提供了一个模板包装器,用于在使用声明的固定目标 char
数组(即 char dst[N]; strcpy_s(dst, src);
)时推导出 size_t
参数。因此,根据语言和供应商,将strcpy
替换为strcpy_s
将在此类用例中正确编译,而编译中断的地方将成为dest 参数的实际原始指针。我不知道该感谢他们还是诅咒他们。【参考方案2】:
鉴于您提供了一个无法推断的附加参数 (size_t destsz
),该参数需要准确才能从更改中受益,您遇到了真正的问题。
一个有 10,000 次使用 strcpy()
的应用程序听起来很疯狂,但你在哪里。
第一 如果您的时间/资源有限,那么我只能建议进行一些风险评估。 哪些调用正在复制外部数据(来自文件、操作系统、用户、端口或套接字等)。 专注于确保那些不会被覆盖,您将更有效地降低风险。
第二 如果您有任何标准变量名称和标准“最大尺寸”,您也许可以进行一些全局搜索和替换。
假设您在您的平台上经常使用filename
并且文件名最多为255 个字符(加上NUL),您可以将strcpy(filename,
替换为(比如说)strcpy_s(filename,FILENAME_MAX_SZ
。
如果代码“到处都是”,你就需要做很多工作。
将strcpy(v,
替换为strcpy_s(v,SIZE_MAX
(使用正则表达式)是一个肤浅的问题,除了可能潜入您的组织代码质量脚本之外,实际上并没有为您带来任何好处。我没有告诉你这样做! ;)
第三
如果您想在 C11 _Generic
的世界中漫步,您可以尝试以下方式:
#define __STDC_WANT_LIB_EXT1__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcpy_s(char *dest,size_t destsz,const char *src)
if(strlen(src)>=destsz)
return 1;
strcpy(dest,src);
return 0;
char *d_strcpy(char *dest,const char *src)
#ifndef NDEBUG
fprintf(stdout,"unsafe copy of %s\n",src);
#endif
return strcpy(dest,src);
#define strcpy(dest,src) _Generic (dest,\
char[100] : strcpy_s(dest,sizeof dest,src),\
char*: d_strcpy(dest,src)\
)
int main(void)
char a[100]='A','B','\0';
char *b=malloc(10*sizeof(char));
strcpy(a,"XXX");
strcpy(b,"XYX");
printf("%s %s\n",a,b);
free(b);
return 0;
不幸的是,您确实需要指定数组大小,因此可能需要使用有限的“最大大小”列表,虽然这应该适用于 Clang(未经测试),但它在 GCC 上失败,因为他们不同意如何解决控制型!见Document: N1930 (controlling expression of _Generic)
狩猎愉快。
【讨论】:
控制类型的东西已经商定。 GCC 是对的。【参考方案3】:为什么要替换 strcpy() 函数? There is nothing wrong with strcpy。教条地将其更改为 strcpy_s
不会解决任何问题。您需要做的是考虑每个案例:
这不是 strcpy
甚至字符串独有的东西,而是代码中每个 数组 都必须考虑的东西。
【讨论】:
以上是关于如何将当前的 strcpy 转换为 strcpy_s?的主要内容,如果未能解决你的问题,请参考以下文章
c语言strcpy将一个结构体的数据复制到另一个后,出问题了