Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 789
zicameau Avatar asked Nov 19 '25 03:11

zicameau


2 Answers

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);
like image 176
Shafik Yaghmour Avatar answered Nov 20 '25 16:11

Shafik Yaghmour


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 
like image 31
Support Ukraine Avatar answered Nov 20 '25 17:11

Support Ukraine



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!