类的对齐规则和结构体很相似,这里以结构体举例
1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到有效对齐数的整数倍的地址处。
注意:有效对齐数 = 编译器默认的一个对齐数 与 该成员所占字节数的较小值。
64位操作系统默认的对齐数为8,32位的为4
3. 结构体总大小为:最大对齐数(所有变量类型所占字节数最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数(该结构体内所有变量类型所占字节数最大者与默认对齐参数取最小)的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
其中编译器默认的对齐数是可以通过#pragma pack (n)来指定对齐数
举例:
- struct C{
- short a;
- double b;
- int c;
- }C;
- printf("%d\n",sizeof(C)); //24
首先第一个变量a放在结构体偏移量为0的地址处,长度是2,存放在0-1的位置
然后看第二个变量b,长度是8,默认对齐参数是8,所以最终对齐就是8,对齐到8*1的位置,存放在8-15的位置
然后看第三个变量c,长度是4,默认对齐参数是8,所以最终对齐数就是4,对齐到4*4的位置,存放在16-20的位置
最后整体对齐,结构体内变量的最大的类型是8,默认对齐参数是8,最终对齐数是8,所以整个结构体的大小就是24
平台原因: 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台对一些特定类型的数据只能从特定的地址开始存取,否则会出现错误,抛出硬件异常等。
性能原因: 有些处理器为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
比如这么一种处理器,它每次读写内存的时候都从某个8倍数的地址开始,一次读出或写入8个字节的数据,假如软件能保证double类型的数据都从8倍数地址开始,那么读或写一个double类型数据就只需要一次内存操作。否则,我们就可能需要两次内存操作才能完成这个动作。