Search code examples
ciobit-fields

Print full uint32_t in hex from struct bitfield


I have a structure like below:

struct myCoolStuff{
    uint32_t stuff1 :  4;
    uint32_t stuff2 :  4;
    uint32_t stuff3 : 24;
    uint32_t differentField;
}

How can I combine these fields into a hex format for printing to the screen or writing out to a file? Thank you.

struct myCoolStuff data = {.stuff1=0xFF, .stuff2=0x66, .stuff3=0x112233, .differentField=99};

printf("my combined stuff is: %x\n", <combined stuff>);
printf("My full field is: %x\n", data.differentField);

Expected Output: 
my combined stuff is: 0xFF66112233 
My different field is: 99

Solution

  • First, you can't get 0xFF out of 0xFF after you put it in a 4-bit variable. 0xFF takes 8 bits. Same for 0x66.

    As for reinterpretting the bitfields as a single integer, you could, in a very nonportable fashion (there's big-endian/little-endian issues and the possibility of padding bits) use a union.

    ( This:

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    struct myCoolStuff{
        union{
            struct {
            uint32_t stuff1 :  4;
            uint32_t stuff2 :  4;
            uint32_t stuff3 : 24;
            };
            uint32_t fullField;
        };
    };
    struct myCoolStuff data = {.stuff1=0xFF, .stuff2=0x66, .stuff3=0x112233};
    
    int main()
    {
        printf("My full field is: %" PRIX32 "\n", data.fullField);
    }
    

    prints 1122336F on my x86_64. )

    To do it portably you can simply take the bitfields and put them together manually:

    This:

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    struct myCoolStuff{
            uint32_t stuff1 :  4;
            uint32_t stuff2 :  4;
            uint32_t stuff3 : 24;
    };
    struct myCoolStuff data = {.stuff1=0xFF, .stuff2=0x66, .stuff3=0x112233};
    
    int main()
    {
        uint32_t fullfield = data.stuff1 << 28 | data.stuff2 << 24 | data.stuff3;
        printf("My full field is: %" PRIX32 "\n", fullfield);
    }
    

    should print F6112233 anywhere where it compiles (uint32_t isn't guaranteed to exist (although on POSIX platforms it will); uint_least32_t would've been more portable.)

    Be careful to make sure data.stuff1 has enough bits to be shiftable by 28. Yours does because it's typed uint32_t, but it would be safer to do it e.g., with (data.stuff1 + 0UL)<<28 or (data.stuff1 + UINT32_C(0))<<28 and same for the second shift.