问题
the following code is not showing the expected output which is garbage value ( strangely the values are swapped )
#include<stdio.h>
int main()
{
float f = 4.6;
int d = 7;
printf("%d %f\n",f,d);
return 0;
}
output: 7 4.600000
回答1:
Let's reduce this a bit:
float f = 4.6;
printf("%d\n", f);
That's undefined behavior. The correct format specifier must be given an argument of the correct type.
Undefined behavior can cause any outcome, including this odd outcome that you are seeing.
Further thoughts:
Now, you might be asking why a compiler would even produce this code. So let's look at the x86-64 assembly for 2 codes:
int main() {
float f = 4.6;
int d = 7;
printf("%d %f\n", d, f);
return 0;
}
int main() {
float f = 4.6;
int d = 7;
printf("%f %d\n", f, d);
return 0;
}
Other than the format string, these two codes produce identical assembly. This is likely because the calling convention requires floats to be placed in different registers than integers, or that floats should be passed on the stack (or any number of other rules that handle floats and integers differently).
This should make it clearer why the code you posted is still producing something useful, even though the code is just broken.
回答2:
The argument corresponding to %d
must be an int
, and the argument corresponding to %f
must be a double. Arguments to variadic functions undergo some standard conversions (so float
will be converted to double
automatically), but they're not automatically converted to the appropriate types for their corresponding printf
format specifiers.
回答3:
Not really hard to understand. The float value is passed in float registers, while the int value is passed in the conventional parameter stack. So when the values are referenced, they are fetched from different areas and it magically works, even though is shouldn't (and won't, on a different box).
回答4:
For example, gcc 4.7.2 for amd64 does this, because integer and floating-point arguments are passed in different registers. This effectively reorders the arguments.
From "System V Application Binary Interface. AMD64 Architecture Processor Supplement. Draft Version 0.99.6" (floating-point numbers have class SSE):
- If the class is INTEGER, the next available register of the sequence %rdi,%rsi, %rdx, %rcx, %r8 and %r9 is used.
- If the class is SSE, the next available vector register is used, the registers are taken in the order from %xmm0 to %xmm7.
Of course you should not do this and enable warnings to catch it during compilation.
来源:https://stackoverflow.com/questions/25535507/strange-output-while-printing-float-as-integer-and-integer-as-float-in-c