I'm familiar with the problems of using bit fields when communicating between processors -- see C/C++: Force Bit Field Order and Alignment and why endian-ness figures into the issue.
But my question is about using bit fields to specify the layout of bits within a one-byte register: Is it safe?
As a concrete example, I'm working with a device with a byte-wide control register documented as follows:
| D7 (msb) | D6 | D5 | D4 | D3:D2 | D1 | D0 (lsb) |
|---|---|---|---|---|---|---|
| Vbias | Mode | Trigger | 3-wire | Fault Code | Fault | 50 Hz |
It would seem natural to define the following struct:
typedef struct {
unsigned int vbias : 1;
unsigned int mode : 1;
unsigned int trigger : 1;
unsigned int wire_3 : 1;
unsigned int fault_code : 2;
unsigned int fault : 1;
unsigned int hz_50 : 1
} control_reg_t;
So the question: As I'm only using this struct within a given processor -- it will not be transmitted over the wire, etc -- is there any reason NOT to use this approach?
update
This is not a good approach for defining bits within a register, even if the struct stays local to one machine. As has been pointed out below, the ordering of the bits is compiler dependent, so vbias may end up as the most significant bit or the least significant bit.
Moral: unless you can guarantee which compiler is used to compile your code, don't use structs and bit fields to define the layout of registers.
The C Standard states that:
This means that whether
vbiasinhabits the most significant bit or least significant bit of the unit (int) is implementation-defined. So unless you are sure you already know the behavior on your system and that you will only use your code on that particular system, bit-fields will not make the cut.As far as I can tell, that is not actually contingent on the byte-order of your system.
Given that your control register specifies which items belong in which bits of significance but C bit-fields do not, I would suggest storing your flags as a
uint8_tif available or otherwise aunsigned char, and access them as follows:And in case setting them the same way you would set the bit-field of a
structis appropriate for your use case:Extracting them manually using bitwise operators will guarantee which item inhabits the LSB, MSB, and each bit in between.