【问题标题】:How should I circumvent -Wformat-truncation?我应该如何规避-Wformat-truncation?
【发布时间】:2019-03-22 09:55:28
【问题描述】:

假设我有一个函数采用 int *p,事实上我知道它只指向 0 到 99 之间的值。但是,编译器不知道这一点,所以如果我写:

char buffer[3];
snprintf(buffer, "%02d", *p);

我收到一个警告(至少在 GCC 8.x 上) - 类似于:

warning: ‘%02d’ directive output may be truncated writing between 2 and 11 bytes into a region of size 2 [-Wformat-truncation=]
   snprintf(buffer, "%02d", *p);

我应该如何规避这个警告?

【问题讨论】:

    标签: printf compiler-warnings truncation format-string gcc8


    【解决方案1】:

    我可以想到三种避免警告的方法:

    1. 使用 GCC pragma 进行局部抑制:

      #if __GNUC__ >= 8
      #pragma GCC diagnostic push
      #pragma GCC diagnostic ignored "-Wformat-truncation"
      #endif
      snprintf(buffer, "%02d", *p);
      
      #if __GNUC__ >= 8
      #pragma GCC diagnostic pop
      #endif
      
    2. 无用地钳制打印值以使编译器知道范围:

      char buffer[3]; 
      int clamped_value = min(max(*p,0),99)` and print that instead of `*p`.
      snprintf(buffer, "%02d", clamped_value);
      
    3. 人为地将缓冲区大小增加了 9 个字节;

      char buffer[3+9]; 
      snprintf(buffer, "%02d", p);
      

    但我不太喜欢这些。第一种方法不太安全(而且更冗长);第二个浪费时钟周期,第三个浪费堆栈空间。

    【讨论】:

      【解决方案2】:

      这段代码在 GCC 8.3.1 上编译并运行良好:

      #include <stdio.h>
      
      #define BUF_SZ 3
      
      int main(void)
      {
          int foo = 99;
          int *p = (int *)&foo;
          char buffer[BUF_SZ];
      
          snprintf(buffer, BUF_SZ, "%02d", *p);
      
          fprintf(stdout, "%s\n", buffer);
      
          return 0;
      }
      
      me@localhost:/tmp$ gcc -v 2>&1 | grep "gcc version"
      gcc version 8.3.1 20190223 (Red Hat 8.3.1-2) (GCC)
      
      me@localhost:/tmp$ gcc -Wall test.c && ./a.out 
      99
      

      也许这个版本的 GCC 没有问题,但我确实在上面注意到你有 snprintf(buffer, "%02d", *p); - 根本不应该编译,因为您缺少 snprintf 的 size 参数。

      此外,值得注意的是,通过以下差异,GCC 8.3.1 确实会按预期抛出错误:

      me@localhost:/tmp$ diff test.c test_format-truncation-warning.c
      11c11
      <     snprintf(buffer, BUF_SZ, "%02d", *p);
      ---
      >     snprintf(buffer, BUF_SZ, "%03d", *p);
      

      对于偶然发现此页面的其他人,他们正在寻找更通用的 -Wformat-truncation 警告“解决方法”。这是一个使用 memcpy() 的方法,尽管我怀疑 -Wformat-truncation 的作者打算将其用作 strncpy() 的替代方法。

      #if USE_STRNCPY
          /* Note that using size of 'NAME_MAX' is just to prevent recent versions
           * of GCC from throwing '-Wformat-truncation' errors.  Otherwise, a char
           * buffer of len UUID_STR_LEN would be fine.
           */
          char tmp_fname[NAME_MAX + 1] = {0};
          strncpy(tmp_fname, input_file_name, NAME_MAX);
      #else
          char tmp_fname[UUID_STR_LEN] = {0};
          memcpy((void *)tmp_fname, (void *)input_file_name,
                 MIN(UUID_STR_LEN - 1, strnlen(input_file_name, UUID_STR_LEN - 1));
      #endif
      

      【讨论】:

      • 这如何回答我的问题?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-15
      • 2012-10-14
      • 2021-08-30
      • 2014-05-26
      • 1970-01-01
      • 2021-10-24
      相关资源
      最近更新 更多