Live data from Hacker News

Packed structs in Zig make bit/flag sets trivial

devlog.hexops.com

31–40 of 147 posts

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

#31

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

Bit fields in C are notoriously non-portable (exact physical layout depends on the compiler). Is Zig any better (apart from the fact that there is only one Zig compiler for now)?

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

#32

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 don't have experience with this area, but...

> this would require that unions can work on the 'bit level' in packed structs

Just as Zig has packed structs, it also has packed unions. So that part shouldn't be an issue.

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

#34

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…

Swift has OptionSet. See https://developer.apple.com/documentation/swift/optionset. It allows setting, testing, or clearing multiple fields with a nice syntax.

One thing that is a bit noisy is that you have to specify the bit index when you name the individual bits, as in (from that article):

  static let secondDay = ShippingOptions(rawValue: 1 
Upside from that is that it makes it clear what bit each value specifies, and won’t easily accidentally change them when you reorder definitions, or insert or remove them. I can see why they made that choice.

I also guess OptionSet could have been implemented in Swift in a third party library, whereas this Zig feature cannot.

I also think/guess neither language guarantees multiple bits would get read or written in one instruction. If your hardware needs that, you probably have to go down a level, or look at the disassembly of your code to check what your compiler did.

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

#35

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

Bit fields in C are notoriously non-portable (exact physical layout depends on the compiler). Is Zig any better (apart from the fact that there is only one Zig compiler for now)?

That's the point of a packed struct: to explicitly declare the physical layout (instead of letting the compiler optimize it). If a packed struct ends up being non-portable between Zig implementations, then my impression is that one and/or the other must have a bug that must be fixed in order to actually comply with the language spec.

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

#36
post #30
post #24

Earlier quoted context omitted.

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.

Meh. Network byte order is big endian. Otoh close to every device uses little endian internally and the conversion is pointless except for convention. Otoh it doesn't really matter, because the conversion is extremely fast (including hardware support in common processors).

Endianness is really perfectly named: a meaningless difference that generations of people fight holy wars over.

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

#37
> This all works, people have been doing it for years in C, C++, Java, Rust, and more. In Zig, we can do better.

We can also do better in those other languages, too. For example, in Rust, I can use a crate like `bitfield` which gives me a macro with which I can write

    bitfield! {
        pub struct Color(u32);
        red, set_red: 0;
        green, set_green: 1;
        blue, set_blue: 2;
        alpha, set_alpha: 3;
    }
Don't get me wrong: it's cool that functionality like this is built-in in Zig, since having to rely on third-party functionality for something like this is not always what you want. But Zig is not, as this article implies, uniquely capable of expressing this kind of thing.

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

#38

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

The order of a bitfield is explicitly implementation defined, at least in C++ [0] and C99. I have been bitten by this when compiling bit-fiddling code with a different compiler (for the same platform).

[0] section "Notes" in https://en.cppreference.com/w/cpp/language/bit_field

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

#39

> This all works, people have been doing it for years in C, C++, Java, Rust, and more. In Zig, we can do better. We can also do better in those other languages, too. For example, in Rust, I can use a crate like `bitfield` which gives me a macro with which I can write bitfield! { pub struct Color(u32); red, set_red: 0; green, set_green: 1; blue, set_blue: 2; alpha, set_alpha: 3; } Don't get me wrong: it's cool that fu…

[deleted]

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

#40
The language I'm working on has the following syntax

  bitfield ColorWriteMaskFlags : u32 {
    red 1 bool,
    green 1 bool,
    blue 1 bool,
    alpha 1 bool,
  };
The number after the field name is the bit size. An (offset, size) pair can be used instead (offsets start at 0 when not explicit). After that can be nothing (the bit field is an unsigned number), or the word 'bool' (the bit field is a boolean) or the word 'signed' (the bit field is a signed number in two's complement). The raw value of the bitfield can always be accessed with 'foo.#raw'.

EDIT: There's also no restriction to how multiple fields can overlap, as long as they all fit within the backing type.

Post reply on HN