printf("line 5: %f\n",98); //output is 0.000000
printf("line 6: %f\n",98.98); //output is 98.980000
printf("line 5: %f\n",98);//though same as first printf statement but output is 98.979980
虽然第一个和最后一个printf语句完全相同,但它们的输出不同。为什么呢?
因为在期待浮动时会将int传递给printf,这就是为什么它工作很奇怪。但我的观点是为什么在最后一个打印声明中,它不是打印一些垃圾值或0,而是使用第二个printf语句的值,这就是打印的内容。
答案 0 :(得分:5)
正如其他人已经说过的那样,将int
传递给printf
,当它期待double
时会导致未定义的行为,并且可能发生任何事情。您可能对为什么程序在第三行打印98.979980
而不是一些随机数的原因感兴趣。
将参数传递给堆栈上的printf
。当第2行将98.98
传递给printf
时,它会被推入堆栈,首先是数字的最低部分。
然后printf
返回,并在第三行再次调用它,现在将98
推入堆栈。在您的体系结构中,int
类型似乎是32位; double
类型的一半大小,因此这只会覆盖早先在堆栈上的98.98
的下半部分。 98.98的上半部分仍在筹码中。
现在,对printf
的第三次调用从堆栈中读取double
。它读取的最重要的一半来自早先在堆栈上的98.98
,而不太重要的一半来自98
的二进制表示;这就是结果如此接近98.98
的原因。由于98是如此小的数字,其最高有效位将为0,并且将98.98
的最不重要的一半设置为大多数为零会给出较小的数字。
如果第3行使用的位数设置为1,则得到的结果大于98.98
。例如,-1的二进制表示将其所有位设置为1,并得到:
printf("line 2: %f\n", 98.98); # 98.98
printf("line 3: %f\n", -1); # 98.980042
如果编译器使用64位整数,或者首先传递具有最高有效部分的double
,或者使用寄存器而不是堆栈来传递参数,则会得到非常不同的结果。
答案 1 :(得分:4)
因为您的程序会调用未定义的行为。 98
的类型为int
,但%f
需要float
(或double
},由于默认促销规则)。
因此,由于printf()
在转换说明符的类型和实际类型不匹配时具有UB,因此对其所做的任何事情都没有合理的解释。
答案 2 :(得分:2)
这是因为%f
需要双参数。给int
是未定义的行为。
ISO/IEC 9899:1999,§7.19.6.1,9:
如果任何参数不是相应转换规范的正确类型,则行为为Undefined。
Undefined behavior指的是行为无法预测的计算机代码。
至少使用gcc,如果启用了警告,您将收到相应的警告:
警告:格式'%f'需要输入'double',但参数2的类型为'int'
答案 3 :(得分:2)
%f
预计double
,但您传递的值为int
。这是未定义的行为。
正确的是:
printf("line 5: %f\n",98.0);
printf("line 6: %f\n",98.98);
printf("line 5: %f\n",98.0);
答案 4 :(得分:1)
如果我们查看编译器生成的代码,我们会看到以下内容:
00401B5E|>MOV DWORD PTR SS:[ESP+0x4],0x62 ; |||
00401B66|>MOV DWORD PTR SS:[ESP],arma_sto.00404024 ; |||ASCII "line 5: %f\n"
00401B6D|>CALL <JMP.&msvcrt.printf> ; ||\printf
00401B72|>MOV DWORD PTR SS:[ESP+0x4],0x51EB851F ; ||
00401B7A|>MOV DWORD PTR SS:[ESP+0x8],0x4058BEB8 ; ||
00401B82|>MOV DWORD PTR SS:[ESP],arma_sto.00404030 ; ||ASCII "line 6: %f\n"
00401B89|>CALL <JMP.&msvcrt.printf> ; |\printf
00401B8E|>MOV DWORD PTR SS:[ESP+0x4],0x62 ; |
00401B96|>MOV DWORD PTR SS:[ESP],arma_sto.00404024 ; |ASCII "line 5: %f\n"
00401B9D|>CALL <JMP.&msvcrt.printf> ; \printf
因为您没有将两个98值转换为float,所以输出是随机的(基于堆栈)。 %f的有效输入是浮点指针编号,它在堆栈上占用两个条目。
第4行不起作用,因为您只提供了一个堆栈条目。
第5行工作正常,因为98.98是一个浮动指针号(需要两个堆栈条目)
第6行输出~98.98,因为00401B7A处的MOV未被撤消。这意味着第6行输出一个有效的浮点数,因为它有两个堆栈条目,但错误的浮动指针数,因为前一个数字还有一部分。
解决方案,强制转换为
printf("line 5: %f\n",(float)98); //output is 98.000000
printf("line 6: %f\n",98.98); //output is 98.980000
printf("line 5: %f\n",(float)98); //output is 98.000000