关于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
的参数。您将 int
值 144
传递给它,因此编译器在将其传递给 sqrt
.
之前自动将 int
转换为 double
但这对于 printf
函数来说 不是 正确的。 printf
接受许多不同类型的参数,只要每个参数都适合它在格式字符串中附带的特定 %
格式说明符,就可以了。所以如果你写
double f = 3.14;
printf("%f\n", f);
有效。但是如果你写
printf("%d\n", f); /* WRONG */
没用。 %d
期望 int
,但您通过了 double
。在这种情况下(因为 printf
是特殊的),编译器没有好的方法来插入自动转换。所以,相反,它只是无法工作。
当它“失败”时,它真的失败。你甚至不一定得到任何“合理”的东西,比如代表你认为你传递的 IEEE-754 浮点数的位模式的整数。如果你想检查 float
或 double
的位模式,你必须用另一种方式来做。
如果您真正想要做的是查看组成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
我是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
的参数。您将 int
值 144
传递给它,因此编译器在将其传递给 sqrt
.
int
转换为 double
但这对于 printf
函数来说 不是 正确的。 printf
接受许多不同类型的参数,只要每个参数都适合它在格式字符串中附带的特定 %
格式说明符,就可以了。所以如果你写
double f = 3.14;
printf("%f\n", f);
有效。但是如果你写
printf("%d\n", f); /* WRONG */
没用。 %d
期望 int
,但您通过了 double
。在这种情况下(因为 printf
是特殊的),编译器没有好的方法来插入自动转换。所以,相反,它只是无法工作。
当它“失败”时,它真的失败。你甚至不一定得到任何“合理”的东西,比如代表你认为你传递的 IEEE-754 浮点数的位模式的整数。如果你想检查 float
或 double
的位模式,你必须用另一种方式来做。
如果您真正想要做的是查看组成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