【发布时间】:2019-01-16 07:02:46
【问题描述】:
我正在尝试了解snprintf,并通过示例找到this answer:
char buf[20] = "";
char *cur = buf, * const end = buf + sizeof buf;
cur += snprintf(cur, end-cur, "%s", "foo");
printf("%s\n", buf);
if (cur < end) {
cur += snprintf(cur, end-cur, "%s", " bar");
}
printf("%s\n", buf);
free(str);
我不清楚的是我们分配了一个固定的硬编码缓冲区大小,这似乎受到缓冲区溢出的影响。在 N1570 中我发现 (7.21.6.5)
1
#include <stdio.h> int snprintf(char * restrict s, size_t n, const char * restrict format, ...);2 snprintf 函数等价于 fprintf,除了 输出被写入一个数组(由参数 s 指定)而不是 到一条溪流。如果 n 为零,则不写入任何内容,并且 s 可能为空 指针。
所以在我看来,习惯用法如下:
int need_space = snprintf(NULL, 0, "abs %s", "fgh") + 1; //How much to allocate?
char *const str = malloc(need_space * sizeof(char)); //allocate
int written = snprintf(str, need_space, "abs %s", "fgh"); //do format
printf("Need space = %d, written = %d\n", need_space, written);
printf("%s\n", str);
或者这并不常见,还有其他问题?
【问题讨论】:
-
它有第二个参数是有原因的。这是一种惯用的 C 方法来尝试避免溢出。
-
没有“静默”截断,请参阅snprintf.3p - Linux manual page,特别注意
"RETURN"部分。您根据缓冲区大小验证返回。 -
根据定义
sizeof(char)是1 -
您展示的内容不一定是人们所做的事情的一个原因是,对数据进行两次格式化需要付出一定的代价,一次是为了找出它需要多长时间,第二次是实际执行格式化。在您使用短固定长度字符串的示例中,成本并不高。对于更复杂的格式、更多参数,尤其是更长的字符串参数,存在一些值得关注的问题(但测量仍然是一个好主意——它到底有多慢?)。一些系统(Linux、GNU C 库)有
asprintf()和vasprintf();使用这些可能是个好主意。 -
同意之前的评论和只是小的补充 - 您的方法需要两次指定相同的格式化字符串,如果复杂的字符串很容易出错,因为使用预处理器定义声明格式字符串也是一种不好的做法.