I have a small question. I have this piece of code:
#include
int main(){
printf(\"%d, %f, %d\\n\", 0.9, 10, \'C\');
}
And
But I would have expected: …
When the format string does not match the types of the arguments in order, the behavior is undefined. Anything can happen. You cannot expect anything (and I do not see why you would expect 0. Maybe you expect printf
to use the format string to convert the arguments between floating-point and integer. It just doesn't. It's a variadic function like you could write your own, and the fact that the format string encodes the types of the trailing arguments is not used to convert them).
Modern calling conventions use registers for the first few arguments, and can use registers even for variadic functions. On x86-64, the convention can be for instance that the first floating-point argument to a variadic function can always be expected in the floating-point register xmm0
, whereas integer arguments are passed in general-purpose registers %rdi
, %rsi
, %rdx
, … This has the effect that printf("%f %d", 1, 1.0)
prints the floating-point argument followed by the integer argument.
As an illustration, here is a short program:
#include
int main(){
printf("%d, %f, %d\n", 0.9, 10, 'C');
printf("%d, %f, %d\n", 10, 0.9, 'C');
}
This is how my compiler (Clang on Mac OS X 10.6) compiles the program:
leaq , %rbx
movq %rbx, %rdi
movsd , %xmm0
movl $10, %esi
movl $67, %edx
movb $1, %al
callq _printf
movq %rbx, %rdi
movl $10, %esi
movsd , %xmm0
movl $67, %edx
movb $1, %al
callq _printf
…
It is clear that the two calls produce the same result. But in the case of one, it is accidental and only “works” for this particular compiler version and ABI, whereas the other one respects the standard and has to work anywhere.
Again, printf("%d %f", 0.9, 10)
is undefined behavior and you should not use it in any circumstances.