0

I have a union that looks similar to the following:

typedef
union _thing
{
    struct thing_indiv {
        uint16_t one:5;
        uint16_t two:4;
        uint16_t three:5;
        uint16_t four:5;
        uint16_t five:6;
        uint16_t six:6;
        uint16_t seven:6;
        uint16_t eight:7;
        uint16_t nine:4;
        uint16_t ten:5;
        uint16_t eleven:6;
        uint16_t twelve:5;
        uint16_t thirteen:5;
        uint16_t fourteen:4;
        uint16_t fifteen:2;
        uint16_t unused:5;
    } __attribute__((packed)) thing_split;
    uint8_t thing_comb[10];
    
} thing;

But it doesn't behave how I expect. I want to assign bytes to thing.thing_comb and retrieve the relevant items from thing.thing_split.

For example, if thing_comb = { 0xD6, 0x27, 0xAD, 0xB6. ..} I would expect thing.thing_split.one to contain 0x1A (the 5 most significant bits of 0xD6, but it does not, it contains 0x16, the 5 least significant bits. I declared each of the fields as uint16_t to keep gcc from complaining about crossing byte boundaries (I experience the same behavior with uint8_t).

Is there a way to lay out this struct to obtain this behavior?

1 Answers1

2

First, type punning with an union in C++ is Undefined Behaviour. Second, the Compiler is free to do anything it wants with a bitfield. It is not forced to lay it out like you want it to.

You need to use regular bit-packing with bitshifts to obtain the behaviour you want.

I had a similar question not so long ago: How to use bitfields that make up a sorting key without falling into UB?

Raildex
  • 3,406
  • 1
  • 18
  • 42