问题描述
我收到以下 gcc 格式截断警告:
test.c:8:33: 警告:'/input' 指令输出可能会被截断,将 6 个字节写入大小在 1 到 20 之间的区域 [-Wformat-truncation=]snprintf(dst, sizeof(dst), "%s-more", src);^~~~~~test.c:8:3:注意:snprintf"输出 7 到 26 个字节到大小为 20 的目标snprintf(dst, sizeof(dst), "%s-more", src);^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这样的代码:
char dst[20];字符源[20];scanf("%s", src);snprintf(dst, sizeof(dst), "%s-more", src);printf("%s
", dst);
我知道它可能会被截断 - 但这正是我首先使用 snprintf 的原因.有没有办法让编译器清楚这是有意的(不使用编译指示或 -Wno-format-truncation)?
- 警告是在 gcc7.1 中添加的,请参阅 gcc7.1 版本更改.
- 来自 gcc 文档:
-Wformat-truncation [...] 的第 1 级仅对调用返回值未使用且很可能导致输出截断的有界函数发出警告.
- 该问题是一份错误报告,已作为 NOTABUG 关闭:
未处理的输出截断通常是程序中的错误.[...]
在预期截断的情况下,调用者通常会检查函数的返回值并以某种方式处理它(例如,通过对其进行分支).在这些情况下,不会发出警告.警告打印的源代码行表明这不是其中一种情况.警告正在执行它的设计目的.
- 但我们可以只检查 snprintf 的返回值,它在出错时返回负值.
#include <stdio.h>#include <stdlib.h>无效f(无效){字符 dst[2],源 [2];//snprintf(dst, sizeof(dst), "%s!", src);int ret = snprintf(dst, sizeof(dst), "%s!", src);如果(ret <0){中止();}//但是我们不喜欢混淆一个班轮吗?for (int ret = snprintf(dst, sizeof(dst), "%s!", src); ret <0;) exit(ret);//我们可以做得更好吗?snprintf(dst, sizeof(dst), "%s!", src) <0 ?中止():(无效)0;//我们不喜欢混淆吗?#define snprintf_nowarn(...) (snprintf(__VA_ARGS__) < 0 ? abort() : (void)0)snprintf_nowarn(dst, sizeof(dst), "%s!", src);}
使用 gcc7.1 gcc7.2 gcc7.3 gcc8.1 在 https://godbolt.org/ 上测试使用 -O{0,1,2,3} -Wall -Wextra -pedantic
.不发出任何警告.gcc8.1 优化/删除对 abort()
的调用,优化程度大于 -O1
.
I'm getting the following gcc format-truncation warning:
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);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on code like this:
char dst[20];
char src[20];
scanf("%s", src);
snprintf(dst, sizeof(dst), "%s-more", src);
printf("%s
", dst);
I'm aware that it might be truncated - but this is exactly the reason why I'm using snprintf in the first place. Is there a way how to make it clear to the compiler that this is intended (without using a pragma or -Wno-format-truncation)?
- The warning was added in gcc7.1, see gcc7.1 release changes.
- From gcc docs:
- The issue was a bug report and was closed as NOTABUG:
- But we can just check the return value of snprintf, which returns a negative value on error.
#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);
}
Tested on https://godbolt.org/ with gcc7.1 gcc7.2 gcc7.3 gcc8.1 with -O{0,1,2,3} -Wall -Wextra -pedantic
. Gives no warning whatsoever. gcc8.1 optimizes/removes the call to abort()
with optimization greater than -O1
.
这篇关于如何规避 GCC 中的格式截断警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!