关于C中printf函数to "output float with %d"的问题

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

我是C语言的新手。今天在学习浮点数的时候,发现了以下问题

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

第一个输出:

9c9e82a0
-1667333472

第二输出:

61ea32a0
1642738336

如上所示,每次执行都会输出不同的结果。查了很多IEEE 754格式,还是不明白是什么原因。想请问有没有人可以解释一下或者提供关键词让我学习一下,谢谢

--------------------------------编辑-------- --------------------------

感谢您的回复。我知道如何打印 IEEE 754 位模式。但是,正如 Nate Eldredge 和 chux-Reinstate Monica 所说,在 printf 中使用 %x 和 %d 是未定义的行为。如果我们的设备中没有浮点寄存器,它是如何工作的?这在 C99 规范中有描述吗?

大多数时候,当您使用“错误种类”(错误类型)的参数调用函数时,会发生自动转换。例如,如果您写

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

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

这很好用。编译器知道(从 <math.h> 中的函数原型)sqrt 函数需要一个类型为 double 的参数。您将 int144 传递给它,因此编译器在将其传递给 sqrt.

之前自动将 int 转换为 double

但这对于 printf 函数来说 不是 正确的。 printf 接受许多不同类型的参数,只要每个参数都适合它在格式字符串中附带的特定 % 格式说明符,就可以了。所以如果你写

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

有效。但是如果你写

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

没用。 %d 期望 int,但您通过了 double。在这种情况下(因为 printf 是特殊的),编译器没有好的方法来插入自动转换。所以,相反,它只是无法工作。

当它“失败”时,它真的失败。你甚至不一定得到任何“合理”的东西,比如代表你认为你传递的 IEEE-754 浮点数的位模式的整数。如果你想检查 floatdouble 的位模式,你必须用另一种方式来做。


如果您真正想要做的查看组成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");

字节排序(“字节顺序”)存在一些问题,但这应该可以帮助您入门。

要打印浮点数的十六进制(即它在内存中的表示方式):

    float TEST= 3.0f;
    int y=0;

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

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

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

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

结果(两者相同):

40400000
1077936128

如您所见,它与您的完全不同。 https://godbolt.org/z/Kr61x6Kv3