printf中的变量转换为double会产生随机输出

时间:2016-11-17 18:03:41

标签: c gcc casting floating-point printf

我试图查看浮点数的十六进制表示,并使用gcc-4.9.2编译此代码:

#include <stdio.h>

int main()
{
  double i = 100;

  printf("%f %x\n", i, (double)i);

  return 0;
}

我很惊讶地发现每次运行代码时,打印出的十六进制值都会发生变化。到底是怎么回事?如何安全地打印浮点数的十六进制表示?

4 个答案:

答案 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