首页 文章

Re Legacy代码:格式'%d'需要类型为'int'的参数,但参数3的类型为'long unsigned int'[-Wformat]

提问于
浏览
3

我经常尝试使用最近的GCC构建大量旧的模拟器和磁盘和磁带归档工具 . 有些错误很容易解决,但我不是一个程序员 .

我明白了:

itstar.c:在函数'addfiles'中:itstar.c:194:4:警告:格式'%d'需要类型'int'的参数,但参数2的类型为'long unsigned int'[-Wformat] itstar . c:194:4:警告:格式'%d'需要类型为'int'的参数,但参数3的类型为'long unsigned int'[-Wformat]

从这段代码片段:

/* add files to a DUMP tape */
/* output buffer must have been initialized with resetbuf() */
static void addfiles(int argc,char **argv)
{
    int c=argc;
    char **v=argv;

    while(c--) {
        addfile(argc,argv,*v++);
    }
    if(verify)
        printf("Approximately %d.%d' of tape used\n",count/bpi/12,
            (count*10/bpi/12)%10);
}

第194行是最后一行,从printf开始 .

该文件是itstar.c,来自tapetools,代码为here .

尽管有警告,它仍会 Build ,但我更愿意知道如何预防它,
因此结果更有效,数据损坏的可能性更小 .

拜托,我错过了什么,需要改变?

先感谢您 .

3 回答

  • 6

    这是undefined behavior,这意味着任何事情都可能发生,包括看似正常工作,然后在路上打破 .

    查看源代码,我们可以看到 countbpi 都是无符号长整数:

    extern unsigned long bpi; /* tape density in bits per inch */
    extern unsigned long count; /* count of tape frames written */
    

    这些的正确格式说明符是 %lu .

    printf的第一个参数指定要打印的字符串,该字符串可以包含以 % 开头的转换说明符,通常指定后续参数的类型,因此在您的示例中:

    "Approximately %d.%d' of tape used\n"
                   ^^ ^^
                   1  2
    

    转换说明符 12 都是 %d ,这意味着 printf 将期望接下来的两个参数的类型为 int ,但它们实际上是 unsigned long 类型 .

    如果我们看一下draft C99 standard section 7.19.6.1 fprintf函数,它也涵盖printf格式说明符,说:

    如果转换规范无效,则行为未定义.248)如果任何参数不是相应转换规范的正确类型,则行为未定义 .

    所以你需要修复不正确的格式说明符,你的警告就会消失,你将回到明确定义的行为领域 .

  • 5

    使用格式说明符 %lu 而不是 %d ,您的编译器应该停止抱怨 .

    printf("Approximately %lu.%lu' of tape used\n", count/bpi/12, (count*10/bpi/12)%10);
    
  • 2

    使用 %lu 而不是 %d . %d 用于 int%lu 用于 unsigned long .

相关问题