I had suggested that proposed approach does not follow strict aliasing rule
Correct. ptrMsg = (Message *)buffer
means that you cannot access the data of ptrMsg
without invoking undefined behavior.
You can prove your point with C17 6.5 §7 (cited here - What is the strict aliasing rule?). An lvalue expression such as ptrMsg->var1 = value
does not access the stored value through a type compatible with the effective type of what's stored there, nor through any of the allowed expressions.
You can however go from Message
to an array of uint8_t
(assuming uint8_t
is a character type) without violating strict aliasing.
The larger problem is however the presence of the bit-field in the first place, which is non-standard and non-portable. For example, you cannot know which part of the bit-field that is the MSB and LSB. You cannot know how the bits are aligned in the 64 bit type. Using a 64 bit type for a bit-field is a non-standard extension. It is endianess-dependent. And so on.
Assuming the 24 bits refer to bit 31 to 8 (we can't know by reading your code), then proper code without strict aliasing violations, bit-field madness and non-standard "struct padding killers" would look like this:
typedef union
{
uint32_t var;
uint8_t bytes[4];
} Message;
uint8_t buffer[4];
Message* ptrMsg = (Message*)buffer;
uint32_t var1 = (ptrMsg->var >> 8);
uint8_t var2 = (ptrMsg->var >> 4) & 0x0F;
uint8_t var3 = (ptrMsg->var) & 0x0F;
Message
being "a union type that includes one of the aforementioned types among its
members". Meaning it contains a type compatible with uint8_t [4]
.
This code also contains no copying and the shifts will get translated to the relevant bit access in the machine code.