结构体中的内存对齐:
总结有两点记下:
1.结构体的长度一定是最长数据元素大小的整数倍;
2.各成员变量存放的起始位置 相对于 结构体的地址 的偏移量 必须为该变量的类型所占字节数的倍数。
默认情况下,为方便对结构体内元素的访问和管理,
1)当结构体内元素的长度 都小于 处理器的位数的时候,便以结构体里面最长的数据元素的大小为对齐单元,即 结构体的长度一定是最长数据元素大小的整数倍;
2)如果结构体内存在长度 大于 处理器位数的元素,那么就以处理器的位数为对齐单位。(一般情况下,不会出现此种情况,CPU 32位)
CPU优化规则大致规则如下:对于n字节的元素(n = 2,4,8.……),它的首地址若能被 n 整除,才能获得最好的性能。
设计编译器的时候可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个满足这个条件的地址作为首地址。
为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。
在默认情况下,VC规定各成员变量存放的起始地址 相对于 结构的起始地址的 偏移量 必须为该变量的类型所占用的字节数的倍数。
一般情况下,记住有下滑线的两行文字就可以了。
1 struct S1 2 { 3 char a; // 1*** 1111 11111111 4 int b; 5 double c; 6 }; 7 struct S2 8 { 9 double a; //11111111 111111111 1******* 10 double b; 11 char c; 12 }; 13 int main() 14 { 15 int i = sizeof(S1); // S1 的大小为:16 16 int j = sizeof(S2); // S2 的大小为:24 17 return 0; 18 }
复杂类型的对齐方式
复杂类型(如结构)的默认对齐方式是它最长成员元素的对齐方式。
例子:
1 #include <cstdio> 2 struct S1 3 { 4 char a; //a 默认按 1 字节对齐,其首地址 偏移量为 1 的倍数 5 long b; //b 默认按 4 字节对齐,其首地址 偏移量为 4 的倍数 6 }; //S1 内存中布局为: 1*** 1111,*表示编译器自动填 7 // 充的空字节,1 表示不是编译器自动填充的字节 8 9 struct S2 10 { 11 char c; // 首地址偏移量 为 0000 12 struct S1 d; // 首地址偏移量 为 0004,对齐方式 按 其元素最长的长度 即4 13 _int64 e; //long long e; //首地址偏移量为 0008 14 }; // 布局: 1*** 1***1111 **** 11111111 15 16 int main() 17 { 18 int i = sizeof(S1); 19 int k = sizeof(S2); 20 printf("%d %d \n",i,k);// i:8,k:24 21 return 0; 22 }
其中结构体S2中S1的默认对齐是按 4 个字节,即其首地址 的偏移量是 4 的倍数,这样能最小化长度。
三点重要:
1.每个成员分别按自己的方式对齐,并能最小化长度
2.复杂类型(如结构)的默认对齐方式是它的最长成员元素的对齐方式,这样当成员是复杂类型时,可以最小化长度
3.对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都是边界对齐。
另外:VC中提供了 #pragma pack(n) 来设定变量以 n 字节对齐。屏蔽掉默认的对齐方式。
n 字节对齐就是说变量存放起始地址的偏移量有两种情况:
1)如果 n 大于等于 该变量所占用的字节数,偏移量必须满足默认的对齐方式,此时,设定不起作用
2)如果 n 小于该变量所占用的字节数,那么偏移量 为 n 的倍数,不满足默认对齐方式。
此时,结构体的总大小变为:1)若n 大于所有成员变量类型的长度,结构体总大小为最大变量长度的整数倍
2)否则为 n 的倍数。
1 #pragma pack(push) //保存对齐状态 2 #pragma pack(4) //设定为4个字节 3 4 struct test 5 { 6 char a; // 按 1 个字节的对齐方式 7 double b; // 按 4 个字节的对齐方式 8 int c; // 按 4 个字节的对齐方式 9 }; 10 #pragma pack(pop) //恢复对齐状态 11 12 int main() 13 { 14 int i = sizeof(test); 15 return 0; 16 }
设定为 4 个字节的对齐方式后 内存布局为: 1*** 11111111 1111,大小为 16
按默认的对齐方式的布局: 1******* 11111111 1111**** ,大小为 24.