简体   繁体   中英

The problem about printf function to “output float with %d” in C

I am a newbie to the C language. When I was learning floating point numbers today, I found the following problems.

float TEST= 3.0f;
printf("%x\n",TEST);
printf("%d\n",TEST);

first output:

9c9e82a0
-1667333472

second output:

61ea32a0
1642738336

As shown above, each execution will output different results. I have checked a lot of IEEE 754 format and still don't understand the reasons. I would like to ask if anyone can explain or provide keywords for me to study, thank you.

-----------------------------------Edit-----------------------------------

Thank you for your replies. I know how to print IEEE 754 bit pattern. However, as Nate Eldredge, chux-Reinstate Monica said, using %x and %d in printf is undefined behavior. If there is no floating point register in our device, how does it work ? Is this described in the C99 specification?

Most of the time, when you call a function with the "wrong kind" (wrong type) of argument, an automatic conversion happens. For example, if you write

#include <stdio.h>
#include <math.h>

printf("%f\n", sqrt(144));

this works just fine. The compiler knows (from the function prototype in <math.h> ) that the sqrt function expects an argument of type double . You passed it the int value 144 , so the compiler automatically converted that int to double before passing it to sqrt .

But this is not true for the printf function. printf accepts arguments of many different types, and as long as each argument is right for the particular % format specifier it goes with in the format string, it's fine. So if you write

double f = 3.14;
printf("%f\n", f);

it works. But if you write

printf("%d\n", f);     /* WRONG */

it doesn't work. %d expects an int , but you passed a double . In this case (because printf is special), there's no good way for the compiler to insert an automatic conversion. So, instead, it just fails to work.

And when it "fails", it really fails . You don't even necessarily get anything "reasonable", like an integer representing the bit pattern of the IEEE-754 floating-point number you thought you passed. If you want to inspect the bit pattern of a float or double , you'll have to do that another way.


If what you really wanted to do was to see the bits and bytes making up a float , here's a completely different way:

float test = 3.14;
unsigned char *p = (unsigned char *)&test;
int i;
printf("bytes in %f:", test);
for(i = 0; i < sizeof(test); i++) printf(" %02x", p[i]);
printf("\n");

There are some issues here with byte ordering ("endianness"), but this should get you started.

To print hex (ie how it is represented in the memory) representation of the float:

    float TEST= 3.0f;
    int y=0;

    memcpy(&y, &TEST, sizeof(y));
    printf("%x\n",y);
    printf("%d\n",y);

or

    union
    {
        float TEST;
        int   y;
    }uf = {.y = 0};

    uf.TEST = 3.0f;
    printf("\n%x\n",(unsigned)uf.y);
    printf("%d\n",uf.y);

Both examples assuming sizeof(float) <= sizeof(int) (if they are not equal I need to zero the integer)

And the result (same for both):

40400000
1077936128

As you can see it is completely different from your one. https://godbolt.org/z/Kr61x6Kv3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM