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 of v1_t {.d1=256};
(C++20) which will obviously truncate the data (put down this way, the current behavior became obvious).
With v2_t
on the other hand, the first data member is data
, hence v2_t {256};
is the equivalent of v2_t {.data=256};
which is yielding the result and behavior I expected.
v1_t
enables brace elision such as {11, 2}
for d1
and d2
fields, 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 consider v2_t
the one providing the "expected" behavior.