3 ms·
This isn't just an issue with GCC but embedded compilers as well. On embedded systems its common to work with packed data structures to maximize serial protocol
by LennyWhiteJr 6y ago
This isn't just an issue with GCC but embedded compilers as well. On embedded systems its common to work with packed data structures to maximize serial protocol efficiency.
Lets say you have a packed structure with a type of
struct MyPackedStruct {
uint8_t byteValue;
uint32_t intValues[5];
}
Normally a compiler would add 3 extra bytes between the uint8_t value and the uint32_t array to keep alignment of the int array, but that won't be the case if you force it to be packed. This results in uint32 values that span two word boundaries. If you access one of those array values in code directly, the compiler is smart enough to perform 2 separate memory reads and combine the resulting value so you don't have to really think about it.
But if you do something like this:
uint32_t *intValues = myPacktedStruct.intValues;
The compiler allows this, but the resulting intValues pointer loses all packed awareness, and trying to dereference that pointer will result in an unaligned memory access exception.
Moral of the story - only use packed data types when serializing/deserializing a protocol stream. Avoid using packed data types 'at rest', because it can cause subtle issues like this. The downside is that it results in extra parsing work when converting between packed and unpacked types.
- loeg 6y agoOr if you're going to use packed structs, pass around a pointer to the full struct instead of to a member.
- Asooka 6y agoI would argue that this is a bug and should probably be fixed in a future C/C++ standard that allows declaring misaligned types. Something like "members of a packed struct have [[aligned(1)]] attribute and cannot be converted to a pointer type with different alignment except with a reinterpret_cast", so you'd have to do uint32_t [[aligned(1)]]*intValues = myPackedStruct.intValues; Would be nice if we also got e.g. float/intNua_t for unaligned types. Any code that gets broken by this change was broken to begin with.
- MaxBarraclough 6y agoForcing packing of a struct isn't possible in standard C, only through compiler extensions. Presumably that's the reason: you have the strange situation where it's legal (and well-defined) to read the member, or to write it, but to take its address and perform a read through that pointer, causes undefined behaviour. I believe that situation is impossible in standard C.