-6

Why does The following code work totally differently on IA-32 and x86-64?

#include    <stdio.h>
int main()  {
     double a   =   10;
     printf("a  =   %d\n",  a);
     return 0;
}

On IA-32, the result is always 0. However, on x86-64 the result can be anything between MAX_INT and MIN_INT.

Martin Gao
  • 61
  • 4
  • 2
    It is undefined behaviour to call `printf` with arguments that do not match the format string. – n. m. could be an AI Jun 13 '16 at 02:15
  • Not really my area, but it looks like on x86-64 `double` and `int` arguments would be passed in different registers -- so `a` gets passed to `printf()` in one place, but when processing the format string `printf()` looks for an `int` argument in a different register which contains garbage since it wasn't used for passing an argument. – Dmitri Jun 13 '16 at 04:35

2 Answers2

1

%d actually is used for printing int. Historically the d stood for "decimal", to contrast with o for octal and x for hexadecimal.

For printing double you should use %e, %f or %g.

Using the wrong format specifier causes undefined behaviour which means anything may happen, including unexpected results.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • You might want to mention the correct formats for type `double`: `"%g"`, `"%f"`, and `"%e"`. – Keith Thompson Jun 13 '16 at 02:22
  • I know the correct format to print double. This is a quesiton asked by my teacher so I think there is something mysterious behind it. Thanks! – Martin Gao Jun 13 '16 at 02:35
  • @MartinGao don't forget to credit this web site with the answer when you turn in your assignment – Raymond Chen Jun 13 '16 at 02:53
  • @RaymondChen Actually it is just an example in a ppt, not related to my assignments. I simply want to know the secrets behind it. It is said that this is an interview question of **Baidu**. – Martin Gao Jun 13 '16 at 03:10
  • @M.M OK~, it is the first time I ask a question on stackoverflow – Martin Gao Jun 13 '16 at 03:16
0

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.

Dmitri
  • 9,175
  • 2
  • 27
  • 34
  • In the x86 case, according to the IEEE754, I know why it is always 0. But, I know little about passing arguments in x86-64 case. I look at the asm code using gdb and find it passes **a** via **%xmm0** so I think you are right. – Martin Gao Jun 13 '16 at 06:12
  • An interesting consequence of this same effect is that you can sometimes pass integer and floating-point arguments in the wrong order and still get normal behaviour. With 64-bit on my system, I get identical results between `printf("%d,%f\n",1234,10.7);` and `printf("%d,%f\n",10.7,1234);` because `1234` is the first `int` (after the format string) and `10.7` is the first `double` no matter which order they're passed in. – Dmitri Jun 13 '16 at 18:54
  • I get the same results on my system. You totally solved my problem and told me what really happens in this undefined behavior~ Thank you~ – Martin Gao Jun 15 '16 at 01:18