snprintf
这个函数是要指定长度,而且编译器会进行越界检查的,所以必须保证目标长度比所有参数加起来长。可是考虑以下程序:
#include <stdio.h>
#include <string.h>
#define LENGTH 1024
int main() {
char cache[LENGTH];
memset(cache, 0, LENGTH);
snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
return 0;
}
这个程序开了-Wall
之后会报错:
test.c: In function ‘main’:
test.c:9:44: error: ‘/ruaruarua’ directive output truncated writing 10 bytes into a region of size 4 [-Werror=format-truncation=]
snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
~~~~^~~~~~
test.c:9:5: note: ‘snprintf’ output 11 or more bytes into a destination of size 4
snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
这个错误是符合预期的,因为确实有可能越界。那么问题来了,我怎样才能完成同样的功能但是不报错呢?
我的gcc
版本比较新,7.1.1
,估计老一点版本的编译器不会报这个错误。
PHP中文网2017-05-27 17:46:46
首先snprintf()
的第二个参数代表的是缓冲区的大小,在这里应该是LENGTH
,sizeof(LENGTH)
的值是4
(我猜你想写的应该是sizeof(cache)
吧)。那么,改成snprintf(cache, LENGTH, "%s/ruaruarua", cache);
之后就行了吗?我们看看这个例子:
#include <stdio.h>
int main()
{
char buf[20] = "hello";
snprintf(buf, 20, "%s world", buf);
puts(buf);
return 0;
}
这个例子企图给buf
末尾添加一个字符串,看看输出
world
并没有达到期望的结果。这是为什么呢?snprintf()
的手册里有这么一段:
Some programs imprudently rely on code such as the following
sprintf(buf, "%s some further text", buf);
to append text to
,buf
. However, the standards explicitly note that the results are undefined if source and destination buffers overlap when callingsprintf()
,snprintf()
,vsprintf()
, andvsnprintf()
. Depending on the version ofgcc(1)
. However, the standards explicitly note that the results are undefined if source and destination buffers overlap when callingsprintf()
,vsprintf()
, andvsnprintf()
. Depending on the version ofgcc(1)
used, and the compiler options employed, calls such as the above will not produce the expected results.家族的函数执行结果将是未定义的。
printf()
即如果原始和目标缓冲区重叠的话,这些
snprintf()
那该如何如何“向一个数组中打印自己原有的内容和一些新的内容”呢?一种方式是把传给
snprintf(buf + strlen(buf), 20, " world");
printf()
那如何连续往缓冲区末尾添加数据呢?注意到家族的函数返回值都是打印的字符数(number of characters printed),那么可以这么调用:
#include <stdio.h>
#include <string.h>
int main()
{
char buf[40];
char *p = buf;
p += sprintf(p, "hello %s\n", "world");
p += sprintf(p, "hello %s", "again");
/* and more similar calls... */
puts(buf);
return 0;
}
结果为🎜
hello world
hello again