As far as I understand, you are allowed to access inactive members of a union, if they share a "common initial sequence" with an active one. This can be used to tag active member with a type field common to all members:
enum command_type {
command_type_foo,
command_type_bar,
};
struct foo_command {
enum command_type type;
int x;
};
struct bar_command {
enum_command_type type;
const char* s;
};
union command {
struct foo_command foo;
struct bar_command bar;
};
// second case means `cmd.foo` was not active, but fine due to CIS
switch (cmd.foo.type) {
case command_type_foo:
return do_foo(&cmd.foo);
case command_type_bar:
return do_bar(&cmd.bar);
}
Is the same true if the common bit is part of a bitfield?
struct i2c_address {
uint32_t is_aux : 1;
uint32_t _reserved : 7;
uint32_t address : 8;
uint32_t offset : 8;
uint32_t length : 8;
};
struct aux_address {
uint32_t is_aux : 1;
uint32_t _reserved : 3;
uint32_t address : 20;
uint32_t length : 8;
};
union address {
struct i2c_address i2c;
struct aux_addredd aux;
};
// is accessing the `is_aux` bit from inactive member UB?
return addr.i2c.is_aux ? do_aux(&addr.aux, buffer) : do_i2c(&addr.i2c, buffer);
.and->. So it is telling us how to understand the text about those operators; they always reinterpret union data. But there is another way to access union members: Via pointers. So, if we have a pointer to a union member that is not the last one written, it may be that reading it has undefined behavior. However, you cannot have a pointer to a bit-field, so this would not apply to the case in the question.)