Print correct format from double value to hexadecimal

0
    #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));
    }

Output:

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

For this line:

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

I want it to print out the result of start[i] The return hexadecimal is not the right value for double. I want it to return 0x40130000000000...

Please help.

c
linux
ubuntu
asked on Stack Overflow Nov 8, 2018 by Toan Tran • edited Nov 8, 2018 by Fiddling Bits

2 Answers

3

The %x format specifier is expecting an unsigned int argument, but you're passing in a double. Using the wrong format specifier invokes undefined behavior.

To print the representation of a double, you need to print each individual byte as hex using a character pointer. This is exactly what you're doing in show_bytes, and is the proper way to do this.

Also, when printing a pointer with the %p format specifier, you should cast the pointer to void *, which is what %p expects. This is one of the rare cases where a cast to void * is needed.

You might be tempted to do something like this:

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

However this is a violation of the strict aliasing rule. You would need to use memcpy to copy the bytes to the other type:

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

You can also do this with a union:

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

union dval v;
v.d = d;
printf("%llx", v.u);
answered on Stack Overflow Nov 8, 2018 by dbush • edited Nov 8, 2018 by dbush
0

To allow printing a hex dump of any object, pass its address and length.

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");
}

Use "%a" to print the significand of the double in hexadecimal.

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

Output

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

User contributions licensed under CC BY-SA 3.0