如何检测 `snprintf` 错误?

2023-11-22

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);
}

这是一部分我可以回答我自己的问题吗?。欢迎其他答案。

如何检测snprintfC 中的错误?

简短回答

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);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何检测 `snprintf` 错误? 的相关文章

随机推荐