打印正确的格式,从双精度值到十六进制

时间:2018-11-08 19:21:54

标签: c linux ubuntu

    #include <stdio.h>

    typedef unsigned char*pointer;

    void show_bytes(pointer start, size_t len)
    {
         size_t i;
         for (i = 0; i < len; i++)
             printf("%p\t0x%04x\n",start+i, start[i]);
         printf("\n");
    }

    int main()
    {
        double a = 4.75;
        printf("Double demo by %s on %s %s\n", "Toan Tran", __DATE__,     __TIME__);
        printf("Double a = %.2f (0x%08x)\n", a, a);
        show_bytes((pointer) &a, sizeof(double));
    }

输出:

Double demo by Toan Tran on Nov  8 2018 11:07:07
Double a = 4.75 (0x00000100)
0x7ffeee7a0b38  0x0000
0x7ffeee7a0b39  0x0000
0x7ffeee7a0b3a  0x0000
0x7ffeee7a0b3b  0x0000
0x7ffeee7a0b3c  0x0000
0x7ffeee7a0b3d  0x0000
0x7ffeee7a0b3e  0x0013
0x7ffeee7a0b3f  0x0040

对于此行:

printf("Double a = %.2f (0x%08x)\n", a, a);

我希望它打印出start[i]的结果 返回的十六进制不是double的正确值。 我希望它返回0x40130000000000 ...

请帮助。

2 个答案:

答案 0 :(得分:3)

%x格式说明符期望使用unsigned int参数,但是您传入的是double。使用错误的格式说明符会调用undefined behavior

要打印double的表示形式,需要使用字符指针将每个单独的字节打印为十六进制。这正是您在show_bytes中所做的,并且是执行此操作的正确方法。

此外,在使用%p格式说明符打印指针时,应将指针强制转换为void *所期望的%p。这是极少数需要强制转换为void *的情况之一。

您可能会想这样做:

printf("%llx", *((unsigned long long *)&a));

但是,这违反了严格的别名规则。您将需要使用memcpy将字节复制到其他类型:

static_assert(sizeof(unsigned long long) == sizeof(double));
unsigned long long b;
memcpy(&b, &a, sizeof(a));
printf("%llx", b);

您也可以通过并集进行操作:

union dval {
    double d;
    unsigned long long u;
};

union dval v;
v.d = d;
printf("%llx", v.u);

答案 1 :(得分:0)

要允许打印 any 对象的十六进制转储,请传递其地址和长度。

void show_bytes2(void *start, size_t size) {
  int nibble_width_per_byte = (CHAR_BIT + 3) / 4;   // Often 2

  unsigned char *mem = start;
  // Highest bytes first
  for (size_t i = size; i>0; ) {
    printf("%0*x", nibble_width_per_byte, mem[--i]);
  }
  printf("\n");

  // Lowest bytes first
  while (size--) {
    printf("%0*x", nibble_width_per_byte, *mem++);
  }
  printf("\n");
}

使用"%a"以十六进制形式显示double的有效数字。

int main() {
  double a = 4.75;
  printf("Double a = %a %e %f %g\n", a, a, a, a);
  show_bytes2(&a, sizeof a);
}

输出

Double a = 0x1.3p+2 4.750000e+00 4.750000 4.75
4013000000000000  // I want it to return 0x40130000000000...
0000000000001340