我可以在我的应用程序中看到许多用于复制字符串的sprintf
。
我有一个字符数组:
char myarray[10];
const char *str = "mystring";
现在,如果我想要将字符串str
复制到myarray
中,最好使用:
sprintf(myarray, "%s", str);
或
strncpy(myarray, str, 8);
发布于 2012-09-05 14:55:54
两者都不应该使用。
sprintf
是危险的,已被弃用,并已被snprintf
取代。将旧的sprintf
安全地用于字符串输入的唯一方法是在调用sprintf
之前测量它们的长度,这很难看,而且容易出错,或者通过添加字段精度说明符(例如,%.8s
或%.*s
,带有额外的整数参数来限制大小)。这也很难看,而且容易出错,特别是当不止一个%s
说明符是involved.strncpy
时,这也是危险的。它不是一个缓冲区大小受限的strcpy
版本。它是一个函数,用于将字符复制到固定长度的空填充(而不是以空结尾)数组中,其中源可以是C字符串或至少与目标大小相同的固定长度字符数组。它的预期用途是用于遗留的unix目录表、数据库条目等,这些表使用固定大小的文本字段,并且不希望在磁盘或内存中浪费一个字节用于null终止。它可能会被误用为缓冲区大小受限的strcpy
,但这样做是有害的,原因有两个。首先,如果整个缓冲区用于字符串数据(即,如果源字符串长度至少与目标缓冲区一样长),则它无法空终止。您可以自己添加终止,但这很难看,而且容易出错。其次,当源字符串比输出缓冲区短时,strncpy
总是用空字节填充整个目标缓冲区。这简直是浪费时间。那么你应该用什么来代替呢?
有些人喜欢BSD的strlcpy
函数。在语义上,它与snprintf(dest, destsize, "%s", source)
相同,只是返回值是size_t
,并且它不会对字符串长度施加人为的INT_MAX
限制。但是,大多数流行的非BSD系统都缺少strlcpy
,而且编写自己的系统很容易出现危险的错误,所以如果您想使用它,您应该从可靠的来源获得一个安全的、已知有效的版本。
我更喜欢对任何非平凡的字符串构造简单地使用snprintf
,而对于一些已经被测量为性能关键型的平凡情况,则使用strlen
+memcpy
。如果您养成了正确使用此习惯用法的习惯,那么意外地编写具有字符串相关漏洞的代码几乎是不可能的。
发布于 2012-09-05 14:28:03
不同版本的printf/scanf都是非常慢的函数,原因如下:
下面是我曾经在barebone 16位低端微控制器上进行的一些测量。
根据经验,您永远不应该在任何形式的生产代码中使用stdio.h。它被认为是一个调试/测试库。MISRA-C:2004在生产代码中禁止stdio.h。
编辑
用事实替换主观数字:
在目标飞思卡尔HCS12,编译器飞思卡尔Codewarrior5.1上对strcpy和sprintf的测量。使用sprintf的C90实现,C99的效率会更低。已启用所有优化。测试了以下代码:
const char str[] = "Hello, world";
char buf[100];
strcpy(buf, str);
sprintf(buf, "%s", str);
执行时间,包括参数混洗开/关调用堆栈:
strcpy 43 instructions
sprintf 467 instructions
分配的程序/ROM空间:
strcpy 56 bytes
sprintf 1488 bytes
分配的RAM/堆栈空间:
strcpy 0 bytes
sprintf 15 bytes
内部函数调用次数:
strcpy 0
sprintf 9
函数调用堆栈深度:
strcpy 0 (inlined)
sprintf 3
发布于 2012-09-05 14:27:50
我不会仅仅为了复制字符串而使用sprintf。这太夸张了,读过这些代码的人肯定会停下来,想知道我为什么要这么做,他们(或我)是否遗漏了什么。
https://stackoverflow.com/questions/12275381
复制相似问题