6 ms·
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 w
by slimsag 4y ago
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
- bananaboy 4y agoI 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.
- flohofwoe 4y ago> 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).
- shultays 4y agoMaybe other members in same struct was enforcing such packing? Such as https://godbolt.org/z/8G4v8McsP https://godbolt.org/z/8G4v8McsP You probably want static asserts for sizes in your code if you are trying to optimize your struct paddings
- flohofwoe 4y agoCould 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).
- jeffreygoesto 4y agoThe 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 https://en.cppreference.com/w/cpp/language/bit_field
- shultays 4y agoInteresting, I saw some low level code that assumes that bits are neatly packed. Some C decisions really confuses me. What would be the point of this one?
- layer8 4y agoThe alignment restrictions for memory accesses on some architectures may prevent bitfields from crossing certain address boundaries, hence implementations may need to reorder and/or pad the fields. The alternative would have been to either fail compilation for bitfield combinations that are incompatible with the target platform, which would arguably be worse, because you couldn’t portably use bitfields at all then, or to force implementations to generate code with case distinctions, possibly depending on the actual alignment at runtime, performing the bitfield accesses using multiple memory accesses if necessary.
- yyyk 4y ago>when I tinkered with C/C++ bitfields, some compilers (at least MSVC I think?) didn't properly pack the bits There's #pragma pack for that.
- bananaboy 4y agoMy 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.
- MobiusHorizons 4y agoMy 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.
- elcritch 4y agoC 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.
- Gibbon1 4y agoFar 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.
- hoseja 4y ago>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.
- wongarsu 4y agoMeh. 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.
- 0x457 4y agoNetwork only applies to information in packet headers. How you actually pack bytes into your packets is entirely up to you and/or the protocol you're using. It was a flip of a coin choice.
- Gibbon1 4y agoThe LoRaWAN standard uses big endian.
- gonzus 4y agoMost, even all of these, sound to me like cargo-culting. I certainly use multiple returns and continue statements all the time. I pass structs by value when I want to stress that they represent a value type that can / should be copied around (for example, a slice). As for the format to send data over a wire, I will either use the ntoh() / hton() macros, or move to a more standard binary format such as protobuffs. The only thing I don't usually run into is the very topic of this article: bit fields.
- 082349872349872 4y agocf K&R 6.9 "Bit-fields"