我试图查看浮点数的十六进制表示,并使用gcc-4.9.2编译此代码:
#include <stdio.h>
int main()
{
double i = 100;
printf("%f %x\n", i, (double)i);
return 0;
}
我很惊讶地发现每次运行代码时,打印出的十六进制值都会发生变化。到底是怎么回事?如何安全地打印浮点数的十六进制表示?
答案 0 :(得分:2)
%x
格式说明符需要类型为unsigned int
的参数。你给它一个double
类型的参数。行为是未定义的,这意味着就C标准而言,可能发生任何 - 包括更改同一格式字符串中其他说明符的输出。
要打印浮点数的十六进制表示,请将其复制到unsigned char
数组并打印数组的元素。
答案 1 :(得分:2)
要打印double的十六进制表示,必须将double转换为char
数组,然后打印每个字节:
double i = 100;
int j;
for (j=0; j<sizeof(double);j++)
printf("%x\n", ((unsigned char *)&i)[j]);
使用((char *)&i)
取i
的地址,并告诉编译器将其解释为指向char
的指针。接下来,将该指针视为char
的数组并将其编入索引。
请注意,使用了类型unsigned char
,因此如果任何字节的最左位设置为1,则在将其传递给int
之前,它不会进行符号扩展。 {1}}。
答案 2 :(得分:1)
格式说明符%x
用于整数类型的对象。它将相应的参数视为unsigned int类型的对象。考虑到对于整数类型的参数,应用整数提升。
因此,当说明符用于浮点数时,函数行为是未定义的。
答案 3 :(得分:1)
如何安全地打印浮点数的十六进制表示?
"%x"
适用于unsigned
等整数。
要查看FP编号的十六进制表示,请使用"%a"
// mis-match between specifier and argument
// v---------^ v-------^
// printf("%f %x\n", i, (double)i);
double i = 0.1;
printf("%f %a\n", i, i);
输出
hexadecimal significant decimal power-of-2 exponent
v-------------v v
0.100000 0x1.999999999999ap-4
或者使用union
union {
double d;
unsigned char uc[sizeof (double)];
} x = {0.1};
for (unsigned i = sizeof x.uc; i > 0;) {
printf("%02X", x.uc[--i]);
}
示例输出 - 取决于endian和其他平台依赖项。 binary64详细信息。
+--------------- MS bit: sign
+-+------------- 11 bit: biased exponent
| |+-----------+ 52-bit: raw fraction
| || |
3FB999999999999A