I will use the following code to explain my question:
typedef struct __attribute__((packed))
{
uint8_t var;
uint16_t array[3];
}struct_t;
uint8_t frame[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD};
volatile struct_t *ptr = NULL;
volatile uint16_t *u16ptr = NULL;
volatile uint16_t a;
volatile uint16_t b;
//******************************************************************************************
int main(int argc, char** argv)
{
ptr = (struct_t*)frame;
u16ptr = ptr->array;
a = ptr->array[0]; // <---- NO Memory Access Exception here
b = *u16ptr; // <---- Memory Access Exception here!
}
In that piece of code, I have forced array
to be memory unaligned to have the memory access exception.
So my question is, why is an "alignment exception" thrown when accessing the unaligned uint16 array through a pointer but not when accessing the array using array subscripts?
None of the resources I've found so far explains why is this if both lines a = ptr->array[0];
and b = *u16ptr;
are accessing the exact same unaligned memory.
Could someone please explain or point in the right direction?
Attempting to read a 16-bit value from an unaligned address will trap on some architecutres. Although the Standard defines the behavior of x[y]
as equivalent to *((x)+(y))
, which would cause an array to be decomposed into a pointer and then fetch a value from that address (trapping if the address isn't aligned), both clang and gcc treat structOrUnion.memberArray[index]
as an lvalue that identifies part of a member of structOrUnion
, as opposed to an expression that decomposes structOrUnion.memberArray
to a pointer, forgets where the pointer came from, and then indexing that.
If the []
operators are used directly on an unaligned array which a member of a "packed" struct, or on any aarray-type member of a union, clang and gcc will do what they need to do to access the storage in question. If, however, such an array is decomposed to a pointer, neither clang nor gcc will reliably allow it to be used to access an object of its type.