Live data from Hacker News

Packed structs in Zig make bit/flag sets trivial

devlog.hexops.com

91–100 of 147 posts

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

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

The (IIRC) ELF specification explicitly recommends against using bitfields because of implementation defined layout.

The compilers often barely document exactly how they lay things out.

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

#92

Earlier quoted context omitted.

It's probably tough to find a metaprogramming solution to this, for two reasons: 1. Addressing happens at the byte level, not the bit level, so a type can't begin on any bit. You'd have to do your own addressing, such as in std::bitset. 2. For now, there's no reflection in the language, so you can't really assign names to members in a general way (hello, preprocessor). A solution might be to index by type; something…

I have done similar things a few times, and like JSON handling, the optimal API does not seem to be the same for every intended use. Size-focused cases want different things than speed-focused ones, and you need to deal with sign extension, etc.

Yup, I'd be very wary of all the template instantiation going on here. Sadly, I often find codegen is the most reasonable solution in a given situation. I wish we had a decent macro system, like Rust's

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

#93

Earlier quoted context omitted.

That's a 'user error'. "Nothing wrong with the language"

If that’s user error, then there’s nothing wrong with C, C++, Java, JavaScript and myriad other languages. Then we don’t need any new ones on the basis of readability, elegance, expressiveness and myriad other subjective properties. Yet many discuss these aspects primarily.

I believe parent was sarcastic and agrees with you.

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

#94

Earlier quoted context omitted.

> I find only two very minor problems with it: firstly, that it’s not commutative Why is that a problem? That is, if a has additional bits set compared to b, then ((a & b) == b) != ((b & a) == a), no?

Of common operators, / and - are the only ones that aren’t commutative. For equality comparisons, there are two opposing conventions: actual == expected (the more popular, in my experience), and expected == actual (by no means rare). Having &== and |== be order-sensitive (though there’s absolutely no question in my mind about what the ordering should be) is mildly unfortunate. It’s very minor.

Yeah ok. I'd consider that just a thing you gotta know. Like how for certain floating point values (a / b) * (c / d) can be fine while (a * c) / (b * d) gives you +/- infinity.

It's a separate operator after all, one I also miss a lot...

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

#95

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)?

Bit fields are portable since ages, since C89. Just pack it, use the smallest base type and don't leave holes. We were using them in perl5 forever, and this compiles on more platforms with more compilers then you know. Just use -mms-bitfields on mingw and use unsigned short instead of just unsigned.

E.g. https://www.nntp.perl.org/group/perl.perl5.porters/2008/02/m... for tricks.

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

#96
post #65
post #62

Earlier quoted context omitted.

> It is not possible to specify bitfields in a way that makes sense, is consistent with a bytewise view of memory, and is portable between big endian and little endian processors. I'm not sure I accept "consistency with a bytewise view of memory" as a well-defined, reasonable concept. I do expect to give a list of bit widths, and get a field that has these in consecutive order. Why would it randomly do weird things o…

> > If the fields are allocated in order, is u4 the low bits of the first byte or the high bits? > It's the low bits on LE, and the high bits on BE. You are advocating for the current rule in C. As I said, C's rule implies 8 bit fields will be in different orders in memory on machines of different endianness, which makes it very difficult to use bitfields to get exact control over memory layout in a portable manner.

No, I'm advocating that the current behavior of C compiler is the only thing that really makes sense for ABI considerations. I opened my comment with: I'm not sure I accept "consistency with a bytewise view of memory" as a well-defined, reasonable concept. You're starting from an assumption that there is something "important" about 8 bit fields, and that bitfields are a tool to express some externally defined memory layout. But unless your language also has "endianed" types for larger integers, it's already impossible to do that. And most languages don't claim or try to work with externally defined memory layouts.

This entire topic disaggregates into 2 distinct categories: deterministic packing for architecture ABIs, which needs to be consistent but can be arbitrary. And representing externally defined structures, which is a matter of exact representation capabilities.

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

#98

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

My apologies, I may have misunderstood what OP meant! I thought they assumed bitfields were always 1-bit in size.

BitInt looks neat. It sounds kind of like a bit array which we use quite a lot (which is as you suggest a class wrapper over an array of uint32_t templated on a size).

We use bitfields quite a bit across clang and MSVC targeting mobile, PC, and console, and haven't had any problems as far as I know.

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

#99
post #57

Earlier quoted context omitted.

I thought you were not able to initialize bitfield members like that in struct. Am I misremembering, was that something else or is it compiler/c++ release dependent?

You can absolutely initialize bitfield members in structs, not sure where your memory is from… maybe it was broken on some specific compiler vendors/versions?

(6): error C7582: 't': default member initializers for bit-fields requires at least '/std:c++20'

It is c++20 apparently https://godbolt.org/z/qvso544dr

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

#100
post #86

Earlier quoted context omitted.

I thought you were not able to initialize bitfield members like that in struct. Am I misremembering, was that something else or is it compiler/c++ release dependent?

This is a c++20 feature

Ah right, I tried again

  (6): error C7582: 't': default member initializers for bit-fields requires at least '/std:c++20'
Nice to see they also improved such "legacy" stuff
Post reply on HN