#include <stdio.h>
int main(void)
{
double resd = 0.000116;
long long resi = 0;
printf("%lld %f %lld %f\n", resd, resd, resi, resi);
return 0;
}
gives (Linux, gcc, x64)
0 0.000116 0 0.000116
^^^^^^^^ odd, since the memory for resi is zeroed
Actually, compiled with g++ it gives random results instead of the second 0.
I understand I gave invalid specifiers to printf and that it triggers unspecified undefined behavior, but I wonder why this specific corruption occurs, since long long and double have the same size.
I get the same results as you do on my machine (Mac OS X, so AMD/Linux ABI). The floating point parameters are passed in XMM registers and the integer parameters in integer registers. When
printfgrabs them usingva_arg, it pulls from XMM when it sees the%fformat, and from the other registers when it sees%lld. Here’s the disassembly for your program as compiled (-O0) on my machine:There you can see what’s going on – the format string is passed in
%rdi, then your parameters are passed (in order) in:%xmm0,%xmm1,%rsi, and%rdx. Whenprintfgets them, it pops them off in a different order (the order specified in your format string). That means it pops them:
%rsi,%xmm0,%rdx,%xmm1, giving the results you see. The2in%eaxis to indicate the number of floating point arguments passed.Edit:
Here’s an optimized version – in this case the shorter code might be easier to understand. The explanation is the same as above, but with a little less boilerplate noise. The floating point value is loaded by the
movsdon line 4.