Strange output when printing float as integer and integer as float in C

the following code doesn't show the expected result, which is a garbage value (oddly enough, the values ​​are swapped)

#include<stdio.h>
int main()
{
    float f = 4.6;
    int d = 7;
    printf("%d %f\n",f,d);
    return 0;
}

      

Yield: 7 4.600000

+3


source to share


4 answers


Let's shorten this a bit:

float f = 4.6;
printf("%d\n", f);

      

This behavior is undefined . The correct format specifier must be given an argument of the correct type.

undefined behavior can lead to any results, including this odd result you are seeing.

Further thoughts:



Now you may be asking why the compiler would even generate this code. Therefore, consider an x86-64 assembly for two codes:

int main() {
    float f = 4.6;
    int d = 7;
    printf("%d %f\n", d, f);
    return 0;
}

int main() {
    float f = 4.6;
    int d = 7;
    printf("%f %d\n", f, d);
    return 0;
}

      

Apart from the format string, these two codes create an identical assembly. This is probably because the calling convention requires floats to fit in different registers than integers, or that floats must be pushed onto the stack (or any number of other rules that handle floats and integers differently).

This should explain why the code you posted is still generating something useful, even if the code is just broken.

+2


source


The matching argument %d

must be int

, and the matching argument %f

must be double. Arguments for variational functions undergo some standard conversions (so float

will be automatically converted to double

), but they will not be automatically converted to the appropriate types for the corresponding format specifiers printf

.



+1


source


It's not hard to understand. The float value is passed in float registers, and the int value is passed on the normal parameter stack. So when values ​​are referenced, they are fetched from different scopes, and this magically works, although it shouldn't (and won't, in another cell).

0


source


For example gcc 4.7.2 for amd64 does this because the integer and floating-point arguments are passed in different registers. This effectively reorders the arguments.

From "System V Application Binary Interface". Appendix to processor architecture AMD64. Version 0.99.6 "(floating point numbers have SSE class):

  • If the class is INTEGER, the next available register in the sequence is% rdi,% rsi,% rdx,% rcx,% r8, and% r9.
  • If the class is SSE, the next available vector register is used, the registers are taken in the order% xmm0 to% xmm7.

Of course, you shouldn't do that and include warnings to catch it at compile time.

0


source







All Articles