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

时间:2013-12-15 03:16:02

标签: c unix gcc printf undefined-behavior

我经常尝试使用最近的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

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

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

提前谢谢。

3 个答案:

答案 0 :(得分: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部分7.19.6.1 fprintf函数,其中也包含printf格式说明符,请说:

  

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

因此您需要修复不正确的格式说明符,并且您的警告将消失,您将回到明确定义的行为领域。

答案 1 :(得分:5)

使用格式说明符%lu代替%d,您的编译器应该停止抱怨。

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

答案 2 :(得分:2)

使用%lu代替%d%d用于int,[{1}}用于%lu