假设我有一个使用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);
我应该如何规避此警告?
答案 0 :(得分:0)
我可以想到三种避免警告的方法:
使用GCC编译指示进行局部抑制:
#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
无用地限制打印值以使编译器知道该范围:
char buffer[3];
int clamped_value = min(max(*p,0),99)` and print that instead of `*p`.
snprintf(buffer, "%02d", clamped_value);
char buffer[3+9];
snprintf(buffer, "%02d", p);
但是我不喜欢这些。第一种方法不太安全(而且比较冗长)。第二个浪费时钟周期,第三个浪费堆栈空间。
答案 1 :(得分:0)
此代码可以在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