此联合声明因总线错误而失败

This union statement fails with a bus error

这会产生一个总线错误:

union { char a[10];
        int i;
      } u;
int *p = (int *) &u.a[1]);
*p = 17;

为什么这会产生错误?我的意思是,chars 可以容纳数字 17。

u.a[1] 未正确对齐 int

通常,访问硬件的内存会一次获得很多位,例如32 位或64 位(四个或八个八位字节)。以 32 为例,当内存和处理器之间交换数据时,字节将以四字节为一组进行移动。例如,处理器将从内存中加载字节 1000、1001、1002 和 1003。

为了适应这一点,处理器的设计使得四字节整数始终位于四的倍数的地址处。当程序想要从地址 1000 加载一个整数时,处理器在单个事务中从内存中获取这些整数,该事务获取字节 1000、1001、1002 和 1003,然后处理器将这些字节传递到寄存器。

要获取单个字节,处理器仍需从内存中获取四个字节,但它可能只将请求的单个字节放入寄存器。

如果并集u在地址1000,那么u.i从地址1000开始,u.a从1000开始,u.a[0]在1000,u.a[1]在1001,u.a[2]在1002,u.a[3]在1003。当你设置p&u.a[1]时,它指向地址1001。当你使用*p,程序尝试从地址 1001 加载 int。然后处理器生成异常,因为 1001 不是 int.

的正确地址

这些是基本的细节。实践中存在差异。一些处理器可能会成功地从 1001 加载一个 int,但它们会比对齐加载慢,因为处理器必须从地址 1000 的内存中获取四字节字和地址处的四字节字1004 然后从第一个字中取出三个字节,从第二个字中取出一个字节并将它们放在一起。在某些系统上,处理器仍然会生成异常,但操作系统通过执行两个加载和合并来处理它,而不是通过向进程传递信号。

C 标准中涵盖此内容的规则在 C 2018 6.3.2.3 7:

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined…

这实际上是说即使程序只是执行转换,行为也是未定义的,(int *) &u.a[1],但通常只有在尝试使用结果指针加载或存储到时才会观察到异常内存。