Why printf() isn't outputting this integer as

2019-01-26 02:08发布

问题:

This question already has an answer here:

  • using printf to print out floating values 3 answers

I have this code:

#include <stdio.h>

int main()
{
    int i = 12345;
    printf("%f", i);

    return 0;
}

printf() will output 0.000000, shouldn't printf() interpret the bits contained in i as a float number?

回答1:

Technically this is undefined behaviour.

You should use a union to do this and print it with %e instead of %f, because it is a small number:

#include <stdio.h>
union int2float
{
  int a;
  float b;
};

int main()
{
    union int2float tmp;
    tmp.a = 12345;

    printf("%e\n", tmp.b);

    return 0;
}

This results in 1.729903e-41.

with %.100f you will get 0.0000000000000000000000000000000000000000172990295420898667405534417057140146406548336724655872023410 as output.



回答2:

This is technically undefined behaviour, so anything can happen, for instance what @Art describes in his answer.

This answer here is therefore an explanation as to what would happen if you tried to print 12345 as a float assuming printf indeed sees the correct 32-bit value.

Let's analyze the binary representation for the number you are trying to represent.

Using http://www.h-schmidt.net/FloatConverter/IEEE754.html we can see that the decimal number 12345 has the following 32-bit representation:

decimal      12345
hexadecimal  0x00003039

Converted bit-to-bit to a IEEE-754 floating point 32-bit value, this represents:

float        1.7299E-41

let's try to print it:

#include <stdio.h>

int main() {
    printf("%f\n", 1.7299E-41);
    return 0;
}

This prints:

0.000000

Now let's read printf man page, as found here: http://linux.die.net/man/3/printf

f, F

The double argument is rounded and converted to decimal notation in the style [-]ddd.ddd, where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is explicitly zero, no decimal-point character appears. If a decimal point appears, at least one digit appears before it.

The 1.7299E-41 value cannot be represented using this flag with the default precision, so the result you get is indeed the correct value.



回答3:

The most likely reason printf doesn't interpret the bits in i as a floating point number is that printf doesn't see i at all. I suspect you're running x86_64 or a similar platform where the arguments are passed to functions in registers. Normally printf would interpret your int as whatever format specifier you gave it. But floating point arguments to functions are handled differently on x86_64 and are put into different registers. So the reason you get 0 as output is that printf pulls out the first floating point argument after the format string instead of the first general purpose register and prints that. Since you haven't used any floating point registers before your call to printf they are most likely zeroed from program start.

Here's an experiment you can try:

#include <stdio.h>

int
main(int argc, char **argv)
{
        printf("%f\n", 17.42);
        printf("%f\n", 0x87654321);
        return 0;
}

I get this output:

$ ./foo
17.420000
17.420000

Having said all that, the only correct answer is: this is undefined behavior, don't do this. But it's interesting to see what's going on under the hood.

If you want to dive into this and are running on Linux/MacOS/*BSD this document, section 3.2.3 describes how arguments are passed to functions (including varargs functions like printf). Windows does things slightly differently, but in this case the result on Windows would be exactly the same. printf on Linux/MacOS/*BSD would expect the argument to be printed in %xmm0 (%xmm1 on Windows) while your call passes it in %rsi (%rdx on Windows).

Of course, if I'm wrong about x86_64, disregard everything I said and look at the answer from @SirDarius, because that applies to many (especially older) architectures. If you're on an alpha, sparc, powerpc, arm, etc. you're on your own. Call printf once with an int, once with a float, disassemble the compiled code and see how arguments are passed.



回答4:

If you want to print an int as float, cast it:

printf("%f", (float)i);


回答5:

The only way printf() knows the data-type of the arguments after the formatting string (and their count) is by reading the format string. The representation of an integer in memory is different from a floating point number. You pass printf() data in the format of an integer number but it assumes the format of a floating point number. This is why you get garbage in the console. You can correct this by type-casting.

printf("%f", (float) i);


回答6:

when you use the %f format specifier you have to use the float variable and print the value. but you have declared i as integer and trying to print using %f it will print some value. As it is a integer you have to use %d specifier. In printf %f will search for the float variable. but there will be no float variable, so it prints some value.

You can type cast the integer value while printing. printf("%f",(float)i);



回答7:

To make i as float type you need to do type cast.

You can use

printf("%f", (float)i);

Example.

float myFloat;
int myInt; 
myFloat = (float)myInt ;        // Type casting


回答8:

Try this

int i = 12345;
printf("%.2f", i/1.0f);