top | item 46748014

(no title)

thechao | 1 month ago

I know this is a bit cursed; but, I always wanted a bitfield-on-steroids construct:

    struct Dang : bits 64    // 64 bits wide, int total
    {
        foo : bits 5 @ 0;    // 5 bits wide at bit offset 0
        bar : bits 5 @ 0;
        baz : bits 16 @ 4;   // 16 bits wide at bit offset 4
        tom : bits 11 @ 32;
    };

discuss

order

a_t48|1 month 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!

titzer|1 month ago

You might want to have a look at the unboxing and packing annotations that are proposed for Virgil. The unboxing mechanism is implemented and there was a prototype of the packing mechanism implemented by Bradley for his thesis. I am working on making a more robust implementation that I can land.

https://arxiv.org/abs/2410.11094

I'm not sure I understand your example; if I am looking at it right, it has overlapping bitfields.

But supposing you didn't want overlapping fields, you could write:

    type Dang(tom: u11, baz: u16, bar: u5, foo: u5) #packed;
And the compiler would smash the bits together (highest order bits first).

If you wanted more control, you can specify where every bit of every field goes using a bit pattern:

    type Dang(tom: u11, baz: u16, bar: u5, foo: u5) #packed 0bTTTTTTTT_TTTbbbbb_bbbbbbbb_bbbzzzzz_????fffff
Where each of T, b, z, and r represent a bit of each respective field.

thechao|1 month ago

Overlapping. I have my needs.

Lvl999Noob|1 month ago

Are you saying you want foo and bar to completely overlap? And baz and foo / bar to partially overlap? And have lots of unused bits in there too?

metaltyphoon|1 month ago

C# can do this with structs. Its kind of very nice to unpack wire data.

sestep|1 month ago

I think you can do this with Virgil, but I'm having trouble finding the exact doc page at the moment: https://github.com/titzer/virgil

titzer|1 month ago

The description is in the paper, but not all of it is implemented.

https://arxiv.org/abs/2410.11094

Bradley implemented a prototype of the packing solver, but it doesn't do the full generality of what is proposed in the paper.

zozbot234|1 month ago

Bitfields are kind of a fake feature because they can't be individually addressed like variables can. So they just turn into inlined getters and setters. Old compilers could not inline arbitrary short functions so bitfields were required as an extra hack, but this is no longer the case today.

_bohm|1 month ago

You can kinda do this with Zig’s packed structs and arbitrary-width integers