代码之家  ›  专栏  ›  技术社区  ›  chux

如何检测'snprintf'错误?

  •  3
  • chux  · 技术社区  · 7 年前
    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);
    }
    
    1 回复  |  直到 7 年前
        1
  •  12
  •   chux    4 年前

    这是 Can I answer my own question? 。欢迎提供更多答案。

    如何检测 snprintf C中的错误?

    简短回答

    回忆起 snprintf() 返回一个 int .

    使用更广泛的 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
    

    OK代码

    如果返回值满足或超过目标数组的大小,则执行一次测试 几乎 足够的

    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.5 3

    健壮的代码会直接检查罕见的错误是否为负值 编码错误 . if (some_int <= some_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 (or encoding error)");
      exit(EXIT_FAILURE);
    }
    

    错配征

    一些编译器警告抱怨比较不同符号的整数,比如gcc -Wsign-compare 具有 智力 尺寸 .投给 尺寸 看起来很合理。

    警告:有符号和无符号整数表达式之间的比较[-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);
    }
    

    迂腐的

    C没有规定 智力 尺寸 . 尺寸 可以是 unsigned short 然后 SIZE_MAX < INT_MAX (据我所知,没有这样的实施。)这是一个演员 (size_t) some_int 可能会改变价值。相反,将正回报值转换为 未签名 ( INT_MAX <= UINT_MAX 始终为true)将不会更改该值,并将确保使用之间最宽的无符号类型进行比较 unsigned 尺寸 .

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