这是一部分我可以回答我自己的问题吗?。欢迎其他答案。
如何检测snprintf
C 中的错误?
简短回答
Recall snprintf()
返回一个int
指示将被写入的字符串的长度或编码错误的负值。
if ((size_t) snprintf(... ) >= sizeof buf) {
error();
}
迂腐地,使用更广泛的size_t
or unsigned
演员,所以更好的是:
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
OK code
单个测试返回值是否满足或超过目标数组的大小是nearly充足的。
char buf[20];
if (snprintf(buf, sizeof buf, "Random int %d", rand()) >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}
负值
The snprintf
函数返回本来应该写入的字符数n
足够大,不计算终止空字符,或者如果发生编码错误则为负值。因此,当且仅当返回值是非负且小于n
。 C11dr §7.21.6.5 3
健壮的代码会直接检查稀有的负值编码错误. if (some_int <= some_size_t)
不幸的是还不够int
将被转换为size_t
. An int
负返回值然后变成大正值size_t
. This usually远大于数组的大小,但未指定如此。
// Pedantic check for negative values
int length_needed = snprintf(... as above ...);
if (length_needed < 0 || length_needed >= sizeof buf) {
fprintf(stderr, "Buffer too small (or encoding error)");
exit(EXIT_FAILURE);
}
符号不匹配
一些编译器警告抱怨比较不同符号的整数,例如 gcc 的-Wsign-compare
with int
and 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 (or encoding error)");
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
始终为真)不会改变该值,并确保使用之间最宽的无符号类型进行比较unsigned
and size_t
.
// Quiet different sign-ness warnings
int length_needed = snprintf(... as above ...);
if (length_needed < 0 || (unsigned) length_needed >= sizeof buf) {
fprintf(stderr, "Buffer too small (or encoding error)");
exit(EXIT_FAILURE);
}