You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GCC中-Wformat-truncation警告含义及非消除式解决方法

问题

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
int main(int argc, char **argv){
    time_t curr_time;
    curr_time = time(NULL);
    struct tm tm = *localtime(&curr_time);
    char file_name[41];
    snprintf(file_name, sizeof(file_name), "backup_%02d.%02d.%02d-%02d.%02d.%02d.tar.lz4.gpg", tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec); 
    printf("%s", file_name);
    return 0;
}

编译警告

执行命令gcc -Wall -O3 ./gen.c时出现以下警告:

./gen.c: In function ‘main’:
./gen.c:11:77: warning: ‘%02d’ directive output may be truncated writing between 2 and 11 bytes into a region of size between 0 and 18 [-Wformat-truncation=]
   11 |     snprintf(file_name, sizeof(file_name), "backup_%02d.%02d.%02d-%02d.%02d.%02d.tar.lz4.gpg", tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
      |                                                                             ^~~~
In file included from /usr/include/stdio.h:894,
                 from ./gen.c:1:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:71:10: note: ‘__builtin___snprintf_chk’ output between 37 and 91 bytes into a destination of size 40
   71 |   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   72 |                                    __glibc_objsize (__s), __fmt,
      |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   73 |                                    __va_arg_pack ());
      |                                    ~~~~~~~~~~~~~~~~~

疑问

  1. 该警告的含义是什么?
  2. 如何在不消除该警告的前提下解决此问题?
解答

警告含义

这个-Wformat-truncation=是GCC的安全警告,触发原因是:

  • GCC基于类型做最坏情况分析:格式串里的%02d对应int类型参数,理论上最多能输出11字节(比如32位int的最大值2147483647是10位数字加符号),叠加格式串的固定部分后,总长度可能达到91字节,远大于你定义的40字节缓冲区。
  • 实际运行时,tm结构体的字段有明确取值范围:日期1-31、月份1-12、年份1900至今(4位)、时分秒0-59(2位),格式化后的字符串实际最多37字节(加终止符\0是38),完全能放进40字节缓冲区,但GCC不考虑实际业务逻辑,只做类型层面的风险提示,所以抛出了这个警告。

不消除警告的解决方法

核心是在运行时确保不会出现截断,同时保留GCC的警告提示:

增加运行时长度校验

调用snprintf后,检查它的返回值:返回值代表格式化后字符串的总长度(不含终止符),如果这个值大于等于缓冲区大小,说明发生了截断,此时直接报错退出,避免使用不完整的文件名:

int ret = snprintf(file_name, sizeof(file_name), 
                   "backup_%02d.%02d.%02d-%02d.%02d.%02d.tar.lz4.gpg", 
                   tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, 
                   tm.tm_hour, tm.tm_min, tm.tm_sec);

if (ret >= sizeof(file_name)) {
    fprintf(stderr, "生成的文件名过长,超出缓冲区限制\n");
    return EXIT_FAILURE;
}

这样即使GCC警告,代码也能在实际出现异常时及时终止,避免错误扩散。

内容的提问来源于stack exchange,提问作者Trevor Philip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:17:57