字节对齐主要是硬件平台的要求,因为对齐的话硬件上实现起来比较简单。反过来说,如果不对齐,那么就有可能因为硬件不支持该操作而触发异常,或者硬件支持,但是实现起来相对比较复杂,导致存取效率不高。譬如32位平台,读取int型数据,如果硬件平台每次读都从偶地址开始,那么要是这个int型数据存放在奇地址开始的地方,就需要读取两次,并且还需要对两次读取结果进行拼装,这样一来肯定慢多了。
一般情况下,也不是特别需要注意字节对齐问题,因为编译器把相关的问题自动处理了。比较明显的是C中的结构体。像结构体
int a;
short b;
char c;
};
在32位平台上,sizeof(struct MyType)值为8,而不是sizeof(a) + sizeof(b) + sizeof(c) = 7。其原因就是编译器为了达到字节对齐的目的,往结构体中加入了隐藏填充字段。该结构体等价于
struct MyType {
int a;
short b;
char c;
char padding; //编译器添加
};
字节对齐与数据类型有关。像32位平台上,
char | short | int,long,float | double | pointer | 结构体,类 | |
自身对齐值 | 1 | 2 | 4 | 8 | 4 | 成员中自身对齐值最大的那个值 |
另外,也可以手工使用#pragma pack (value)指令来设置一个指定对齐值。实际生效的对齐值将是自身对齐值和指定对齐值中小的那个值。
字节对齐相关的也主要是需要意识到这个概念,在设计结构时可以注意节省空间,同时尽力避免编译器自动填充引发的隐患。比较简单的方式就是可以像网络协议一样,画个表格,然后把各字段填进去。这样结构一目了然,有多少填充/保留字段也很明确(对于这些字段也该主动赋予名字,而不是让编译器来完成)。一般是合理安排,使此类字段尽可能的少或者日后有扩展意义。