I have following union in C++
union MsgData {
struct
{
uint32_t msb : 1;
uint32_t reg_addr : 7;
uint32_t data : 8;
uint32_t fill : 3;
uint32_t crc : 5;
} bits;
uint8_t bytes[3];
};
In case I do following (address
contains 26
, data
contains 255
- both in decimal):
msg.bits.msb = 1;
msg.bits.reg_addr = (address & 0x7F);
msg.bits.data = data;
msg.bits.fill = 0;
msg.bits.crc = 0;
the byte array bytes
inside the union MsgData
contains:
msg.bytes[0]: 53
msg.bytes[1]: 255
msg.bytes[2]: 0
I have expected 154
value in the msg.bytes[0]
. Can anybody give me an advice why I have got 53
instead of 154
value in the msg.bytes[0]
?
The behaviour of your program is undefined because you read from an inactive member of the union.
How to use union in C++ correctly?
In general: By only reading from the active member of the union which is the one that was assigned last. Exceptions do exist. For example, reading from inactive member that has the same type as the active member is also allowed. There are no such exceptions that would apply to your program.
Since you want to pun the type into array of bytes, there is another, well defined way: reinterpret_cast
:
struct
{
...
} bits;
static_assert(std::is_same_v<uint8_t, unsigned char>);
uint8_t* bytes = reinterpret_cast<uint8_t*>(&bits);
Note that this reading through this bytes
pointer is allowed specifically because unsigned char
(along with a few other types) is special.
Now, assuming that you use a language extension that defines the behaviour of union type punning or use the reinterpret_cast
shown above:
Can anybody give me an advice why I have got 53 instead of 154 value in the msg.bytes[0]?
Because of this:
reg_addr | msb | bit field
7654321 | 0 | bit index in order of significance
0011010 | 1 | bit value
0b00110101 == 53
It is unclear why you had expected otherwise. Relying on order of bit fields is not portable.