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,代码在这里.
尽管有警告,它仍会构建,但我更愿意知道如何防止它,
因此结果更有效,并且数据损坏的可能性更小.
拜托,我错过了什么,需要改变?
先感谢您.
这是未定义的行为,这意味着任何事情都可能发生,包括出现正常工作,然后在路上打破.
查看源代码,我们可以看到两者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)
两者的转换说明1和2是%d,这意味着printf将预计未来两个参数是类型的int,但他们是真正类型unsigned long.
如果我们看一下草案C99标准部分7.19.6.1 fprintf函数,它也涵盖了printf格式说明符,说:
如果转换规范无效,则行为未定义.248)如果任何参数不是相应转换规范的正确类型,则行为未定义.
所以你需要修复不正确的格式说明符,你的警告就会消失,你将回到明确定义的行为领域.
使用格式说明符%lu代替,%d编译器应该停止抱怨.
printf("Approximately %lu.%lu' of tape used\n", count/bpi/12, (count*10/bpi/12)%10);
Run Code Online (Sandbox Code Playgroud)