Live data from Hacker News

Packed structs in Zig make bit/flag sets trivial

devlog.hexops.com

21–30 of 147 posts

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

#21
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, the expression will resolve to 'true' if any of the Alpha or Blue bits are set.

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

#23
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

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 alway…

C Bitfields are fairly common in embedded code. While layout can vary across compilers and archs hardware driver writers assume a known arch and compiler. You really can't compile embedded targets with say msvs or clang. Also gcc seams to be the defacto compiler for most embedded nowadays.

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

#24
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

Far as I can tell 'don't use bit fields' is something students learn from their CS professors along with don't use goto, multiple returns, continue statements, pass structs by value, and always convert to big endian when sending data over a wire.

My experience is C compilers have ways packing and defining the order of bitfields and structs.

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

#25
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.

[deleted]

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

#26

Earlier quoted context omitted.

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 (…

Maybe other members in same struct was enforcing such packing? Such as https://godbolt.org/z/8G4v8McsP

You probably want static asserts for sizes in your code if you are trying to optimize your struct paddings

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

#27

Earlier quoted context omitted.

> 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 (…

Maybe other members in same struct was enforcing such packing? Such as https://godbolt.org/z/8G4v8McsP You probably want static asserts for sizes in your code if you are trying to optimize your struct paddings

Could also be that MSVC has improved in this area. I think I experimented with VS2015 (since this was my 'base line compiler' at the time).

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

#28

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…

I've come to really like Nim's built-in `set` type for that sorta scenario. It's just a bit-vector but it took me months before I realized that. You can cast an `int32` to a `set[MyEnum]` and be able to do set unions, differences, etc. Makes it easy to define a mask just by `const myMask = {A, B, E}`.

Making a Zig BitSet would probably be doable, for those cases where bitfields are overkill.

1: https://nim-lang.org/docs/manual.html#types-set-type

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

#29
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.

In C I'm using a macro for stuff like that (improving readability, avoiding errors). In Zig I could use a `comptime` function, I presume?

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

#30
post #24
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

Far as I can tell 'don't use bit fields' is something students learn from their CS professors along with don't use goto, multiple returns, continue statements, pass structs by value, and always convert to big endian when sending data over a wire. My experience is C compilers have ways packing and defining the order of bitfields and structs.

>always convert to big endian when sending data over a wire

What is this awful advice. Only convert to big-endian where legacy demands it.

Post reply on HN