Minimal example:
union v1_t
{
struct {
unsigned int d1 : 4;
unsigned int d2 : 4;
unsigned int : 8;
};
unsigned short data;
};
union v2_t
{
unsigned short data;
struct {
unsigned int d1 : 4;
unsigned int d2 : 4;
unsigned int : 8;
};
};
int main()
{
v1_t v1 {256}; // gets truncated to 0. This is the equivalent of v1_t {.d1=256}
v2_t v2 {256};
}
The exact representation of my bitfields is different and is irrelevant here. The important part is that v2_t works as I expect and require (2 Bytes info with bitfields), butv1_t is truncating the data into 4 bits, exactly d1?
The uniform initialization of the fields of each union will follow the order of the declared members.
For instance,
v1_t {256};is the equivalent ofv1_t {.d1=256};(C++20) which will obviously truncate the data (put down this way, the current behavior became obvious).With
v2_ton the other hand, the first data member isdata, hencev2_t {256};is the equivalent ofv2_t {.data=256};which is yielding the result and behavior I expected.v1_tenables brace elision such as{11, 2}ford1andd2fields, respectively, but I have many different bit fields of different sizes and initialization must remain consistent from type to type.The current standard in use in my project is C++17, hence the
{.data}initialization possibility is not available and that is the reason why I considerv2_tthe one providing the "expected" behavior.