← Back to context

Comment by a_t48

7 hours ago

It is a bit cursed, but you can do this in C/C++.

https://godbolt.org/z/vPKEdnjan

    union Dang
    {   
        uint64_t : 64; // set total width
        uint8_t foo : 5;
        uint8_t bar : 5;
        struct __attribute__((packed)) {
            uint8_t : 4;
            uint16_t baz : 16;
        };
        struct __attribute__((packed)) {
            uint32_t : 32;
            uint16_t tom : 11;
        };
    };

The member types don't actually matter here so we can have a little fun and macro it without having to resort to templates to get "correct" types.

    #define OFFSET_BITFIELD_DECLARE(NAME, SIZE) \
        union NAME { \
            uint64_t : SIZE

    #define BITFIELD_MEMBER(NAME, SIZE, OFFSET) \
        struct __attribute__((packed)) { \
            uint64_t : OFFSET; \
            uint64_t NAME : SIZE; \
        }

    #define OFFSET_BITFIELD_END() }

    OFFSET_BITFIELD_DECLARE(Dang, 64);
        BITFIELD_MEMBER(foo, 5, 0);
        BITFIELD_MEMBER(bar, 5, 0);
        BITFIELD_MEMBER(baz, 16, 4);
        BITFIELD_MEMBER(tom, 11, 32);
    OFFSET_BITFIELD_END();

Highly recommend not doing this in production code. If nothing else, there's no compiler protection against offset+size being > total size, but one could add it with a static assert! (I've done so in the godbolt link)

Edit: if you're talking about Zig, sorry!