一、结构体对齐
在计算结构体大时往往需要考虑到结构体对齐,简单的总结下我的一些经验。
结构体对齐时,先找出本结构中最大类型的长度,先考虑自身对齐,最后考虑整个结构对齐(把最大类型长度看做模数来对齐,32位下模数最大为4),下面用图解法进行分析:
例:(64位系统,模数最大为8,所以结构体最大对齐值为8 ; 32位系统最大模数为4,结构体对齐值最大为4)
#include <stdio.h>
struct A
{
char a; //1
int c; //4
double b; //8
};
struct B
{
char a; //1
double b; //8
int c; //4
};
void main()
{
struct A x;
struct B y;
printf("%d,%d\n",sizeof(x),sizeof(y));
}
64位输出结果:16 , 24
32位输出结果:16,16
对于64位系统:
解析:
首先,64位系统,最大类型为double长度为8,所以确定结构体对齐值为8。
1、对于结构体A:
首先,放char a ,字节长度为1,然后放int b(长度为4),1+4 = 5 < 8 ,下一个要存放的是 double类型,所以不够了,另外存放一块为8的空间所以总大小为
5 +1 +3(填充部分)+8 = 16 。
2、对于结构体B:
首先放char型 ,占 1 个位置;下一个要放的double占8个字节,不够放了,,所以填充7个字节。double找下一块空间放,刚好占满8。再存放int (4字节),最后占了20字节空间,然后需要与结构体对齐(模数为8),所以最后结果为24。
1(char) +7(填充部分)+8 (double)+4+4(模数对齐后填充部分) = 24
对于32系统
解析:
结构体A和B大小都为 16 。
每个数据对 模数4对齐,不够的话用两块单位为4的块来存,小于4 ,对4对齐,最后结构体总大小对4 对齐。
对于结构体A:
1(char)+3 (填充部分) + 4 (int) +8(double) = 16
对于结构体B
1 (char)+3(填充部分)+8(double) + 4 (int) = 16 (已对齐)
二、位域:
位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。
记住:位域不能跨字节
例题1:int :0表示相面出现的类型不能够再往里面填充。
struct area
{
int a:3;
int:0; //告诉下面,20不能够放到a的那块存储区域去了
int c:20;
};
所以该结构体大小为 4 + 4 = 8;如果没有 int : 0那一句,则大小为4.
例2: int : x 表示占用几个为,占用部分不可用,但是接下来的位可继续往上面填充。
struct area
{
int a:3;
int:4; //告诉下面,如果我们总大小没超过32,你可以继续填充a的区域
int c:20;
};
所以该结构体大小为 4 。
例题3 位域不能跨字节,**位域需要跟结构体最长类型对齐,前面的类型应自动对齐,然后再进行填充。
struct area
{
char a:6; //向int对齐,扩展为32位
char b:3;
int c:20;
};
结构体大小 :8
struct area //64位,向double对齐
{
char a:6;
long b:63;
char c:3;
};
结构体大小为:24
注意:short为2,作为模数,用于对齐位域是对最长的数据对齐,
struct area //对short对齐,扩展为16位
{
char a:2;
short b:10;
char c:3;
};
结果为:2
如果把 3 改为7,结果就变为 4 了,因为最后c也需要对short对齐。