EDIT: I already knew that printf is not typesafe I am just looking for an explination about what exactly ocurred (I mean describe the undefined behavior).
Why if I print "7" in the second printf, the program prints 9.334354. I know that if I don't write 7.0, this won't be printed but Why does it take the first number writted instead?.
#include <stdio.h>
int main()
{
printf("%.2f\n", 9.334354);
printf("%.5f\n", 7);
printf("%03d\n", 9);
getchar();
}
This is the output
9.33
9.33435
009
Repeat this to yourself for two weeks once a night before going to bed:
printf is not typesafe. printf is not typesafe. printf is not typesafe.
The function will only work if you pass it an argument of the type that you promise. Everything else is undefined behaviour. You promise a double
(via %f
) but provide an int
(the type of the literal 7
), so it's undefined behaviour. Shame on you.
(I did once go into details to explain the actual output, in case you're interested.)
Update: Since you're interested in the explanation for this particular behaviour, here's the (relevant) assembly for that code on my x86/GCC4.6.2/-O3:
First the data sections:
.LC0:
.long 1921946325
.long 1076013872 // 0x 4022AB30 728E92D5 is the binary rep of 9.334354
.LC1:
.string "%.2f\n"
.LC2:
.string "%.5f\n"
.LC3:
.string "%03d\n"
Now the code:
fldl .LC0 // load number into fp register
fstpl 4(%esp) // put 64-bit double on the stack
movl $.LC1, (%esp) // first argument (format string)
call printf // call printf
movl $7, 4(%esp) // put integer VA (7) onto stack
movl $.LC2, (%esp) // first argument (format string)
call printf // call printf
movl $9, 4(%esp) // put integer VA (9) onto stack
movl $.LC3, (%esp) // first argument (format string)
call printf // call printf
The reason you see what you see is simple now. Let's for a moment switch to full 17-digit output:
printf("%.17f\n", 9.334354);
printf("%.17f\n", 7);
We get:
9.33435399999999937
9.33435058593751243
Now let's replace the integer by the "correct" binary component:
printf("%.17f\n", 9.334354);
printf("%.17f\n", 1921946325);
And voila:
9.33435399999999937
9.33435399999999937
What happens is that the double
occupies 8 bytes on the stack, of value 0x4022AB30728E92D5
. The integer only occupies 4 bytes, and as it happens, the least significant four bytes are overwritten, so the floating point value is still nearly the same. If you overwrite the four bytes with the same bytes that occur in the original float, then you get the exact same result.
I might add that it's pure luck that the most significant four bytes remain intact. In different circumstances, they might have been overwritten with something else. In short, "undefined behaviour".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With