Passing an argument to printf()
that doesn't match the format specifiers in the format string is undefined behaviour... and with undefined behaviour, anything could happen and the results aren't necessarily consistent from one instance to another -- so it should be avoided.
As for why you see a difference between x86 (32-bit) and x86-64, it's likely because of differences in the way parameters are passed in each case.
In the x86 case, the arguments to printf()
are likely being passed on the stack, aligned on 4-byte boundaries -- so when printf()
processes the %d
specifier it reads a 4-byte int
from the stack, which is actually the lower 4 bytes from a
. Since a
was 10 those bytes have no bits set, so they're interpreted as an int
value of 0.
In the x86-64 case, the arguments to printf()
are all passed in registers (though some would be on the stack if there were enough of them)... but double
arguments are passed in different registers than int
arguments (such as %xmm0 instead of %rsi). So when printf()
tries to process an int
argument to match the %d
specifier, it takes it from a different register that the one a
was passed in, and uses whatever garbage value was left in the register instead of the lower bytes of a
, and interprets that as some garbage int
value.