4 ms·
> How would you do [packed structs] in C? Bitfields! This is valid C: struct foo { unsigned bg_priority: 2; unsigned character_base: 2; // ...
by dropbear3 2y ago
> How would you do [packed structs] in C?
Bitfields! This is valid C:
struct foo {
unsigned bg_priority: 2;
unsigned character_base: 2;
// ...
};
- purple-leafy 2y agoBut C/ C-compilers don't guarantee your struct wont have holes (by default), so you may have to do something like __attribute__((packed)) to ensure they are packed structs: struct bitmap_file_header { UWord signature; UDWord file_size; UWord reserved_1; UWord reserved_2; UDWord file_offset_to_pixel_array; } __attribute__((packed));
- travisgriggs 2y agoThere’s also a directive (don’t have code in front of me) that you can do at file level that will cause all subsequent struct defs to be packed… #push(pragma(pack(0)) ?? I’ve done a lot of direct register access in C this way. I do like Zigs ability to just define the different sizes though.
- mananaysiempre 2y agoIt’s MS(V)C syntax, now supported by GCC and Clang as well: #pragma pack(push) #pragma pack(1) /* ... */ #pragma pack(pop) The first two lines can also be condensed into #pragma pack(push, 1)
- dropbear3 2y agoThis is not true of adjacent bitfields, at least for C99: An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 6.7.2.1 § 10
- mananaysiempre 2y agoThat’s usually something your ABI will describe in fairly precise terms, though if (as in your example) you want non-naturally-aligned fields, you may indeed want to both use a packed struct and prepare for alignment faults on less-tolerant architectures.
- MobiusHorizons 2y agoin microcontrollers it's very common to see code generated that creates structs for the registers. They will typically output fields that are a full machine word in size (or maybe in some cases as small as a byte), and individual bits will be addressed with bitmasking (ie `my_device.some_reg |= SOME_REG_FLAG_NAME` or `my_device.some_reg &= ~SOME_REG_FLAG_NAME` to clear it). It is sometimes necessary to be thoughtful about batching writes so that certain bits are set before the periferal begins some process. A trivial example would be: port_a.data_out |= GPIOA_PIN_1 | GPIOA_PIN_2; and port_a.pin1 = true; port_a.pin2 = true;
- kevin_thibedeau 2y agoThis is why manufacturers don't do this for volatile register access. You now have bloated, hazard prone code with multiple read-modify-writes.