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

Kuz*_*uze 3 c unix printf gcc 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);
}
Run Code Online (Sandbox Code Playgroud)

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

该文件是itstar.c,来自tapetools,代码在这里.

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

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

先感谢您.

Sha*_*our 6

这是未定义的行为,这意味着任何事情都可能发生,包括出现正常工作,然后在路上打破.

查看源代码,我们可以看到两者count并且bpi无符号长的:

extern unsigned long bpi; /* tape density in bits per inch */
extern unsigned long count; /* count of tape frames written */ 
Run Code Online (Sandbox Code Playgroud)

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

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

"Approximately %d.%d' of tape used\n"
               ^^ ^^
               1  2
Run Code Online (Sandbox Code Playgroud)

两者的转换说明12%d,这意味着printf将预计未来两个参数是类型的int,但他们是真正类型unsigned long.

如果我们看一下草案C99标准部分7.19.6.1 fprintf函数,它也涵盖了printf格式说明符,说:

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

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


Fid*_*its 5

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

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