Display bit pattern of double as hex?

I am trying to use printf in order to print the binary representation of a double onto the console. Here is the code that I have so far:

#include <stdio.h>

int main()
{
    double a = 4.75;
    unsigned long long b = *(unsigned long long *) &a;
    printf("Double a = %f (0x%x)" a, b);
}

I also tried changing it from a long long to a long instead. Here is the result that I get from doing this in gcc linux:

Double a = 4.750000 (0x0)

I'm pretty sure since my system is little endian that it is only grabbing the first 32 bits which are all zeroes. However, I'm not sure how to fix this.

I thought it might have been because long is 64 bit in linux but after testing that I got the same result again. Maybe I'm printing it incorrectly? Not sure, let me know and thanks for your time.

728x90

3 Answers Display bit pattern of double as hex?

In C, code like

unsigned long long b = *(unsigned long long *) &a;

is illegal as it violates a rule called strict aliasing about pointers of one type referencing objects of a different type.

However, there is on exception: a char pointer may alias any object

So using char pointer, you can do something like this in C:

#include <stdio.h>

int main()
{
    double a = 4.75;
    unsigned char* p;

    // Method 1 - direct memory read
    p = (unsigned char*)&a;
    for (size_t i=0; i < sizeof(double); ++i)
    {
        printf("%02x ", *p);
        ++p;
    }
    printf("\n");

    // Method 2 - reversed memory read
    size_t i = sizeof(double);
    p = (unsigned char*)&a + i - 1;
    do
    {
        printf("%02x ", *p);
        --p;
        --i;
    } while(i > 0);

    return 0;
}

Output:

00 00 00 00 00 00 13 40 
40 13 00 00 00 00 00 00

The two methods prints with different endianness.

If you don't like pointers, you can as an alternative use a union. Like:

#include <stdio.h>

int main()
{
    union
    {
        double a;
        char c[sizeof(double)];
    } d;
    d.a = 4.75;

    for (size_t i=0; i < sizeof(double); ++i)
    {
        printf("%02x ", d.c[i]);
    }
    printf("\n");

    size_t i = sizeof(double);
    do
    {
        --i;
        printf("%02x ", d.c[i]);
    }
    while (i > 0);
    printf("\n");


    return 0;
}

Output:

00 00 00 00 00 00 13 40 
40 13 00 00 00 00 00 00 

4 months ago

Your code has two issues, the simple one is that you are using the wrong format specifier %llx is the correct specifier for unsigned long long. Both clang and gcc provide a warning for this using -Wall, see it live.

The second issue is that you are violating the strict aliasing rule here:

unsigned long long b = *(unsigned long long *) &a;

the correct way to type-pun (in both C and C++) is to use memcpy (see it working live):

std::memcpy( &b, &a, sizeof(double));

At the strict aliasing link above notes in C++20 we should get bit_cast which will simplify type-punning e.g.:

b = bit_cast<unsigned long long>(a);

4 months ago

In C++:

double a = 4.75;
char tmp[sizeof(double)];
memcpy(tmp, &a, sizeof(double));
... // print individual bytes as hex

Alternatively:

double a = 4.75;
unsigned char* tmp = reinterpret_cast<unsigned char*>(&a);
for (int i = 0; i < sizeof(double); i++)
  ... // print *(tmp + i) as hex

4 months ago