Live data from Hacker News

Packed structs in Zig make bit/flag sets trivial

devlog.hexops.com

11–20 of 147 posts

Re: Packed structs in Zig make bit/flag sets trivial

#11
post #6

This is a nice syntax, but the functionality seems essentially the same as bit fields in C. Does this provide anything additional?

Admittedly I didn't know C had bit fields like that, so I didn't cover them. I've never seen them used in practice and I've used quite a lot of C libraries. I wonder why that is? One major difference appears to be that C bitfields memory layout is compiler-dependant. The other major difference is Zig's arbitrary-bit-width integer types just leading to less footguns I would speculate

My impression was that for interfacing with hardware, the memory layout isn’t always contiguous, leaving gaps for reserved fields, so people just use the explicit syntax shown in the article. I had been under the impression the layout of bit fields was guaranteed (much like struct fields) but if that is truly compiler specific as you say, I can see why it would not be useful for interfacing with hardware. I had always thought it was because embedded c sometimes deals with less capable compilers, so people often limit themselves to c89 or even older standards.

Re: Packed structs in Zig make bit/flag sets trivial

#13
post #6

Earlier quoted context omitted.

Admittedly I didn't know C had bit fields like that, so I didn't cover them. I've never seen them used in practice and I've used quite a lot of C libraries. I wonder why that is? One major difference appears to be that C bitfields memory layout is compiler-dependant. The other major difference is Zig's arbitrary-bit-width integer types just leading to less footguns I would speculate

I don't know why you haven't come across them but personally I've used bitfields a lot over my career as a video game programmer at different companies. You can have arbitrary bit width integers as well. It's not really very different to zig.

> You can have arbitrary bit width integers as well.

This is news to me, how? AFAIK they'll only eventually make it into C23 with _BitInt(N).

...and apart from building a C++ wrapper class of course, but how would this pack with data outside the class - like the 4 + 28 bits example in the blog post.

Also IIRC when I tinkered with C/C++ bitfields, some compilers (at least MSVC I think?) didn't properly pack the bits (e.g. a single bit would be padded to a full byte, or they couldn't agree on a common size of the containing integer - e.g. one compiler packing <8 number of bits into an uint8_t, and another into a uint32_t). In the end C/C++ bitfields weren't all that useful for the use case described in the blog post, at least if portability across the three big compilers is needed (gcc, clang, msvc).

Re: Packed structs in Zig make bit/flag sets trivial

#15
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

"WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue" creates a number with both the alpha and blue bits set, then "mask &" (that number) ands the mask with that number in which both bits are set, so it'll only return true if both alpha and blue are set. The parenthetical grouping of the operators is key here.

edit: oh, i think i'm wrong, nevermind.

Re: Packed structs in Zig make bit/flag sets trivial

#16
One area where this is still less flexible than regular bit masking is that quite often I want to access groups of bits as a value. For instance if the bits represent in/out pins on a chip emulator, sometimes I want to access unique data bus pins, and sometimes I want to set or get the data bus value.

Maybe Zig can handle this case with unions though, I haven't tried this yet (this would require that unions can work on the 'bit level' in packed structs).

Re: Packed structs in Zig make bit/flag sets trivial

#17
post #5

Earlier quoted context omitted.

D just went ahead and implemented bit fields. They work, and it's hard to find any way to improve on them.

It also specified the layout (little endian) and disallowed reordering / padding / etc.

How bitfields are allocated within a byte is related, but independent from endianness.

endianness: how an array of bytes is interpreted as an integer/how an integer is layed out in memory as an array of bytes.

bitfield allocations: how subsequent bitfields are allocated within an integer, typically starting from least significant bit to most significant, or the other way around.

Re: Packed structs in Zig make bit/flag sets trivial

#18
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

Yes it would need to be:

    if ((mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { ... }
...which is quite a mouthful.

Re: Packed structs in Zig make bit/flag sets trivial

#19
post #15
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

"WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue" creates a number with both the alpha and blue bits set, then "mask &" (that number) ands the mask with that number in which both bits are set, so it'll only return true if both alpha and blue are set. The parenthetical grouping of the operators is key here. edit: oh, i think i'm wrong, nevermind.

No it won't. & is "binary and" and result will be WGPUColorWriteMask_Alpha or WGPUColorWriteMask_Blue if only one of them is set. Which is non zero so evaluated to true. So it checks either or those flags

Correct usage would be if you want both flags.

    (flag & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)

Re: Packed structs in Zig make bit/flag sets trivial

#20
post #15
post #7

if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { // alpha and blue are set.. } Doesn't this give you if alpha OR blue is set? Errors like this are another reason syntactical sugar for readability is important.

"WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue" creates a number with both the alpha and blue bits set, then "mask &" (that number) ands the mask with that number in which both bits are set, so it'll only return true if both alpha and blue are set. The parenthetical grouping of the operators is key here. edit: oh, i think i'm wrong, nevermind.

I believe it would need to be something like if (mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) for both bits to be set here.
Post reply on HN