如何规避GCC中的格式截断警告?

Mar*_*zer 12 c format gcc gcc-warning

我收到以下gcc格式 - 截断警告:

test.c:8:33: warning: ‘/input’ directive output may be truncated writing 6 bytes into a region of size between 1 and 20 [-Wformat-truncation=]
snprintf(dst, sizeof(dst), "%s-more", src);
                             ^~~~~~
test.c:8:3: note: ‘snprintf’ output between 7 and 26 bytes into a destination of size 20
snprintf(dst, sizeof(dst), "%s-more", src);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

像这样的代码:

char dst[20];
char src[20];
scanf("%s", src);
snprintf(dst, sizeof(dst), "%s-more", src);
printf("%s\n", dst);
Run Code Online (Sandbox Code Playgroud)

我知道它可能会被截断 - 但这正是我首先使用snprintf的原因.有没有办法让编译器明白这是预期的(不使用编译指示或-Wno格式截断)?

Kam*_*Cuk 13

  1. 警告已经入侵gcc7.1,请参阅gcc7.1发布的更改.
  2. 来自gcc docs:

-Wformat-truncation [...]的级别1仅警告对有效函数的调用,这些函数的返回值未使用,并且很可能导致输出截断.

  1. 问题是错误报告,并作为NOTABUG关闭:

未处理的输出截断通常是程序中的错误.[...]
在期望截断的情况下,调用者通常检查函数的返回值并以某种方式处理它(例如,通过分支).在这些情况下,不会发出警告.警告打印的源代码行表明这不是其中之一.警告正在做它的设计目的.

  1. 但是我们可以检查snprintf的返回值,它会在出错时返回负值.

#include <stdio.h>
#include <stdlib.h>
void f(void) {
    char dst[2], src[2];
    // snprintf(dst, sizeof(dst), "%s!", src);

    int ret = snprintf(dst, sizeof(dst), "%s!", src);
    if (ret < 0) {
         abort();
    }

    // But don't we love confusing one liners?
    for (int ret = snprintf(dst, sizeof(dst), "%s!", src); ret < 0;) exit(ret);
    // Can we do better?
    snprintf(dst, sizeof(dst), "%s!", src) < 0 ? abort() : (void)0;
    // Don't we love obfuscation?
#define snprintf_nowarn(...) (snprintf(__VA_ARGS__) < 0 ? abort() : (void)0)
    snprintf_nowarn(dst, sizeof(dst), "%s!", src);
}
Run Code Online (Sandbox Code Playgroud)

测试https://godbolt.org/与gcc7.1 gcc7.2 gcc7.3 gcc8.1与-O{0,1,2,3} -Wall -Wextra -pedantic.没有任何警告.gcc8.1优化/删除对abort()优化更大的调用-O1.

  • 注意,`snprintf()`仅在出错时返回负数。在截断时,如果缓冲区足够长,它将返回将要写入的字符数。 (3认同)

Dan*_*com 8

此错误仅在*printf调用长度受限的函数时触发(例如snprintfvsnprintf)。换句话说,这并不表示您可能会溢出缓冲区,就像 sprintf 可能发生的那样;它只通知您您没有检查是否snprintf正在执行其工作和截断。

知道了这一点,我对使用 全局禁用它更加乐观-Wno-format-truncation,而不是试图哄骗gcc忽略特定实例。

  • @AlexisWilke如果我不关心它是否被截断,为什么我必须测试它?这就像使用“max()”函数,然后被迫测试是否确实达到了限制。 (2认同)

Bas*_*irk 6

该页面对我很有用:
https://www. Fluentcpp.com/2019/08/30/how-to-disable-a-warning-in-cpp/

您可以通过执行以下操作解决 gcc/clang 编译器的问题:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
    snprintf(dst, sizeof(dst), "%s-more", src);
#pragma GCC diagnostic pop
Run Code Online (Sandbox Code Playgroud)

上面的网页还提供了 Visual Studio 编译器警告的解决方案。

  • 他们可以通过从海湾合作委员会中删除这些废话来解决问题。如果我们截断 sprintf 中的内容,那是因为我们希望它被截断(例如小时和日期,我们知道它永远不会是“十亿”,最多只是“31”;)并且不,我们不应包含“pragmas” '在我们的代码中纯粹是为了'GCC',而它也应该与其他所有东西一起编译。它以前从未存在过。现在可以再次将其删除。哦,顺便说一句。如果我不指定 -Wall 我不想看到警告。特别是不是关于我如何尝试将日期放入 %d 字段;) 当一个月有 20 亿天时我会回复他们。 (2认同)