As commentators note, the line printf("%f\n", 5 / 2); just demonstrates undefined behavior. But let's see why you can get such results on the x86-64 architecture using System V ABI.
The short answer is that the first few arguments are passed through registers. The choice depends on the type of argument: integer arguments go to the "classical" registers ( edi , esi , etc.), Floating point go to the SSE registers ( xmm0 , xmm1 , etc.).
Since we put the wrong type in the format string, printf reads the argument from the wrong case.
Simplify your program as follows:
#include <stdio.h> int main(void) { printf("%f\n", 5/2); printf("%f\n", 5.0/2); printf("%f\n", 5/2); return 0; }
Now let's move on to disassembling main . We start with the prologue function, which is not too special:
push %rbp mov %rsp,%rbp sub $0x10,%rsp
Then we get our first call to printf , where the arguments are passed to edi (which receives a pointer to a format string) and esi ( 5/2 , which is 2 due to integer division):
mov $0x2,%esi mov $0x4005e4,%edi mov $0x0,%eax callq 4003e0 < printf@plt >
However, printf will read the format "%f\n" and try to read the argument from xmm0 . In my case, this register has a value of 0 , so this outputs 0.000000 .
In the second call, the argument is obviously a floating point number that goes through xmm0 :
movabs $0x4004000000000000,%rax mov %rax,-0x8(%rbp) movsd -0x8(%rbp),%xmm0 mov $0x4005e4,%edi mov $0x1,%eax callq 4003e0 < printf@plt >
Now printf prints the expected 2.500000 (which you see here as 0x4004000000000000 , which corresponds to the 64-bit floating point constant for 2.5). We pass it through xmm0 , and it reads it from xmm0 .
The third call exactly matches the first:
mov $0x2,%esi mov $0x4005e4,%edi mov $0x0,%eax callq 4003e0 < printf@plt >
What has changed is that printf calls did not change the value in xmm0 . It still contains the constant 2.5 from the second call, since we call printf the third time. In the third call, printf will print 2.500000 again.
(And our function ends with a boring return 0 , of course :)
mov $0x0,%eax leaveq retq