简体   繁体   English

C中printf函数“用%d输出浮点数”的问题

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

I am a newbie to the C language.我是 C 语言的新手。 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.查了很多IEEE 754格式,还是不明白原因。 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.我知道如何打印 IEEE 754 位模式。 However, as Nate Eldredge, chux-Reinstate Monica said, using %x and %d in printf is undefined behavior.然而,正如 Nate Eldredge、chux-Reinstate Monica 所说,在 printf 中使用 %x 和 %d 是未定义的行为。 If there is no floating point register in our device, how does it work ?如果我们的设备中没有浮点寄存器,它是如何工作的? Is this described in the C99 specification?这是否在 C99 规范中描述?

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 .编译器知道(从<math.h>的函数原型) sqrt函数需要一个double类型的参数。 You passed it the int value 144 , so the compiler automatically converted that int to double before passing it to sqrt .您将int144传递给它,因此编译器会在将它传递给sqrt之前自动将该int转换为double

But this is not true for the printf function.但对于printf函数来说,情况并非如此。 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. printf接受许多不同类型的参数,只要每个参数都适合它在格式字符串中使用的特定%格式说明符,就可以了。 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 . %d需要一个int ,但你传递了一个double In this case (because printf is special), there's no good way for the compiler to insert an automatic conversion.在这种情况下(因为printf是特殊的),编译器没有好的方法来插入自动转换。 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.你甚至不一定得到任何“合理”的东西,比如代表你认为通过的 IEEE-754 浮点数的位模式的整数。 If you want to inspect the bit pattern of a float or double , you'll have to do that another way.如果要检查floatdouble的位模式,则必须以另一种方式进行。


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的位和字节,这是一种完全不同的方式:

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)两个例子都假设sizeof(float) <= sizeof(int) (如果它们不相等,我需要将整数归零)

And the result (same for both):结果(两者相同):

40400000
1077936128

As you can see it is completely different from your one.如您所见,它与您的完全不同。 https://godbolt.org/z/Kr61x6Kv3 https://godbolt.org/z/Kr61x6Kv3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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