I was recently writing C++ code (which I don’t do much any more) for a little microcontroller to talk to an Allegro A6281 LED driver IC. It uses a 32-bit word to either set the driver PWM duty cycle, or a different 32-bit word to set some other properties. None of the subfields in the words align on 8-bit boundaries (note the MSBit is on the right):
The four bytes of this word are sent over a SPI bus to the LED driver IC.
I had initially tried to implement this with bit fields in C++ (well, I tried a union of both but could never get that to pack into four bytes):
struct Color {
uint8_t ignore : 1;
uint8_t address : 1;
uint16_t red : 10;
uint16_t green : 10;
uint16_t blue : 10;
} __attribute__((packed));
I was worried about endianness issues too, but figured I could solve those. Unfortunately, it turns out C/C++ don’t guarantee that bits are packed tightly or in order (which forces me to question the point of them at all), and no combination of pragmas I could find would tell the compiler to do the right thing.
Sure, this could be accomplished with shifting and masking, but in an embedded environment, the low-level performance of splitting bits mid-word and copying them to other arbitrary bits in another word might be suboptimal.
I wonder if Swift, could not be enhanced with a more useful notion of bit fields. I’d love to be able to declare a struct as fitting into a particular number of bytes, define its arbitrary bitfields in order, assign to or read those bit field’s values, and finally, get the individual bytes of the structure in specific order (this would mean specifying the endianness of the resultant layout in some way, or for reading/writing).
Expressing this at a high level would make it easier for the developer, obviously, but would also make it much easier for the compiler to apply any special bit-level instructions the target architecture might have. If the programmer is forced to write their own masking and shifting, it might make it impossible to take advantage of such instructions.
This would have benefits for memory-mapped IO as well, as many embedded control registers are broken up into bit fields.