为什么在使用指针访问未对齐的 uint16 数组时抛出 "alignment exception" 而在使用下标访问数组时不抛出?

Why is an "alignment exception" thrown when accessing an unaligned uint16 array with a pointer but not when accessing the array using subscripts?

我将使用以下代码来解释我的问题:

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!
}

在那段代码中,我强制array内存未对齐以产生内存访问异常。

所以我的问题是,为什么在通过指针访问未对齐的 uint16 数组时抛出 "alignment exception" 而在使用数组下标访问数组时不抛出?

到目前为止我发现的

None 资源解释了为什么 a = ptr->array[0];b = *u16ptr; 行都访问完全相同的未对齐内存。

有人可以解释一下或指出正确的方向吗?

尝试从未对齐的地址读取 16 位值会陷入某些架构师的陷阱。尽管标准将 x[y] 的行为定义为等同于 *((x)+(y)),这将导致数组被分解为指针,然后从该地址获取值(如果地址未对齐则捕获) , clang 和 gcc 都将 structOrUnion.memberArray[index] 视为标识 structOrUnion 成员的一部分的左值,而不是将 structOrUnion.memberArray 分解为指针的表达式,忘记指针来自何处,然后对其进行索引。

如果 [] 运算符直接用于 "packed" 结构成员的未对齐数组,或联合的任何数组类型成员,clang 和 gcc 将执行它们的操作需要做的访问有问题的存储。但是,如果这样的数组被分解为指针,则 clang 和 gcc 都不会可靠地允许使用它来访问其类型的对象。