很多 CPU ,如基于 Alpha, IA-64, MIPS, 和 SuperH 体系的,拒绝读取未对齐数据。当一个程序要求其中之一的 CPU 读取未对齐数据时,这时 CPU 会进入异常处理状态并且通知程序不能继续执行。举个例子,在 ARM, MIPS, 和 SH 硬件平台上,当操作系统被要求存取一个未对齐数据时默认通知应用程序一个异常。
对齐性
对齐性是一种内存地址的特性,表现为内存地址模上 2 的幂。例如,内存地址 0x0001103F 模 4 结果为 3 ;这个地址就叫做与 4n + 3 对齐, 4 指出了所选用的 2 的幂的值。内存地址的对齐性取决于所选择的关于 2 的幂值。同样的地址模 8 结果为 7 。
一个内存地址符合表达式 Xn + 0 ,那么就说该地址对齐于 X 。
CPU 执行指令就是对存储于内存上的数据进行操作,这些数据在内存上是以地址为标记的。对于地址来说,单独的数据会有其占用内存的字节数。如果它的地址对齐于它 的字节数,那么就称作该数据自然对齐,否则称为未对齐。例如,一个标记 8 字节的浮点数据的地址对齐于 8 ,那么这个数据就自然对齐。
数据对齐性的编译处理
设备编译器以一种防止造成数据未对齐的方式来对数据进行地址分配。
对于单个的数据类型,编译器为其分配的地址是数据类型字节数的倍数。因此,编译器分配给 long 型变量的地址为 4 的倍数,就是说以 2 进制表示地址的话,最后两位为 0 。
另外,编译器以一种自然对齐每个结构成员的方式来填充结构体。参看下面的代码里面的结构体 struct x_ 。
编译器填充这个结构以使其自然对齐。
例如
下面的代码说明了编译器是如何在内存中填充的。
两种定义在作sizeof(struct x_)运算都会返回12字节。
第二种定义含有两种填充成分:
*char _pad0[3]使得int b 在4字节边界上对齐
*char _pad1[1]使得结构数组struct _x bar[3]对齐。
填充使得bar[3]各个变量能够自然对齐。
下面的代码显示了bar[3]的内存结构:
对齐性
对齐性是一种内存地址的特性,表现为内存地址模上 2 的幂。例如,内存地址 0x0001103F 模 4 结果为 3 ;这个地址就叫做与 4n + 3 对齐, 4 指出了所选用的 2 的幂的值。内存地址的对齐性取决于所选择的关于 2 的幂值。同样的地址模 8 结果为 7 。
一个内存地址符合表达式 Xn + 0 ,那么就说该地址对齐于 X 。
CPU 执行指令就是对存储于内存上的数据进行操作,这些数据在内存上是以地址为标记的。对于地址来说,单独的数据会有其占用内存的字节数。如果它的地址对齐于它 的字节数,那么就称作该数据自然对齐,否则称为未对齐。例如,一个标记 8 字节的浮点数据的地址对齐于 8 ,那么这个数据就自然对齐。
数据对齐性的编译处理
设备编译器以一种防止造成数据未对齐的方式来对数据进行地址分配。
对于单个的数据类型,编译器为其分配的地址是数据类型字节数的倍数。因此,编译器分配给 long 型变量的地址为 4 的倍数,就是说以 2 进制表示地址的话,最后两位为 0 。
另外,编译器以一种自然对齐每个结构成员的方式来填充结构体。参看下面的代码里面的结构体 struct x_ 。
- Code: Select all
struct x_
{
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
} MyStruct;
编译器填充这个结构以使其自然对齐。
例如
下面的代码说明了编译器是如何在内存中填充的。
- Code: Select all
// Shows the actual memory layout
struct x_
{
char a; // 1 byte
char _pad0[3]; // padding to put 'b' on 4-byte boundary
int b; // 4 bytes
short c; // 2 bytes
char d; // 1 byte
char _pad1[1]; // padding to make sizeof(x_) multiple of 4
}
两种定义在作sizeof(struct x_)运算都会返回12字节。
第二种定义含有两种填充成分:
*char _pad0[3]使得int b 在4字节边界上对齐
*char _pad1[1]使得结构数组struct _x bar[3]对齐。
填充使得bar[3]各个变量能够自然对齐。
下面的代码显示了bar[3]的内存结构:
- Code: Select all
adr
offset element
------ -------
0x0000 char a; // bar[0]
0x0001 char pad0[3];
0x0004 int b;
0x0008 short c;
0x000a char d;
0x000b char _pad1[1];
0x000c char a; // bar[1]
0x000d char _pad0[3];
0x0010 int b;
0x0014 short c;
0x0016 char d;
0x0017 char _pad1[1];
0x0018 char a; // bar[2]
0x0019 char _pad0[3];
0x001c int b;
0x0020 short c;
0x0022 char d;
0x0023 char _pad1[1];