int snprintf(char * restrict s, size_t n, const char * restrict format, ...);
snprintf()
可以很好地防止超出目标s
。但是,当目的地不足以得到完整结果时,如何检测到该错误和其他错误?
以下条件是否足够?
char buf[11 + 10 + 1];
if (snprintf(buf, sizeof buf, "Random int %d", rand()) >= sizeof buf) {
fprintf(stderr, "Buffer too small"); // Maybe `int` was 64-bit?
exit (EXIT_FAILURE);
}
答案 0 :(得分:8)
这是Can I answer my own question?的一部分。欢迎提供其他答案。
如何检测C中的
snprintf
错误?
使用size_t
或unsigned
转换中的较大者。
if ((size_t) snprintf(... ) >= sizeof buf) {
error();
}
或学步地
int length_needed = snprintf(... );
if (length_needed < 0 || (unsigned) length_needed >= sizeof buf) {
error();
}
测试截断
有时候,从snprintf()
中检测出被截断的字符串是非常重要的。
char buf[13];
char *command = "format_drive";
char *sub_command = "cancel";
snprintf(buf, sizeof buf, "%s %s", command, sub_command);
system(buf); // system("format_drive") leads to bye-bye data
确定代码
一次测试返回值是否达到或超过目标数组的大小就足够了。几乎。
char buf[20];
if (snprintf(buf, sizeof buf, "Random int %d", rand()) >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}
负值
snprintf
函数返回如果n
足够大时将要写入的字符数,不计算终止的空字符,如果出现编码错误,则返回负数。因此,当且仅当返回值是非负且小于n
时,以零结尾的输出已被完全写入。 C11dr§7.21.6.53
严格的代码会直接检查负值,以解决罕见的编码错误。不幸的是,if (some_int <= some_size_t)
是不够的,因为int
将转换为size_t
。 int
的负返回值然后变为大的正size_t
。通常,该 远大于数组的大小,但尚未指定。
// Pedantic check for negative values
int length_needed = snprintf(... as above ...);
if (length_needed < 0 || length_needed >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}
符号不匹配
一些编译器警告抱怨将不同符号的整数(例如gcc的-Wsign-compare
与int
和size_t
进行比较。强制转换为size_t
。
警告:有符号和无符号整数表达式[-Wsign-compare]
的比较
// Quiet different sign-ness warnings
int length_needed = snprintf(... as above ...);
if (length_needed < 0 || (size_t) length_needed >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}
pedantic
C没有指定int
的正值是size_t
的子范围。 size_t
可以是unsigned short
,然后是SIZE_MAX < INT_MAX
。 (我知道没有这样的实现。)因此,对(size_t) some_int
的强制转换可以更改该值。相反,将正返回值强制转换为unsigned
(INT_MAX <= UINT_MAX
始终为true)不会更改该值,并且将确保使用unsigned
和{{1之间的最大无符号类型进行比较。 }}。
size_t