1.对齐规则:
1.结构体的第一个成员对齐到结构体变量的起始位置(偏移量为0处)。
2.其它成员要对齐到对齐数的整数倍的地址处(编译器默认对齐数(vs默认为8,gcc没有默认只看变量)与该成员变量所占字节的较小值。)
3.结构体总大小为最大对齐数的整数倍
4.如果嵌套了结构,则该嵌套的结构体的最大对齐数是自己成员中最大对齐数的那一个的整数倍处。第3条规则就改为了还要看结构体里面的成员的最大对齐数,和非嵌套的那部分的成员,所有成员中对齐数最大的那一个
例子:
1.
struct stu {
char c1;
char c2;
int n;
}
最终总共消耗了8个字节的空间,刚好是最大对齐数 4(int n存放对应的),所以如果用
sizeof(struct stu) 会等于8
2.
struct stu {
char c1;
int n;
char c2;
}
与刚刚那个略微有一点点不一样的是占了9个字节,不为4的整数倍,所以要转化为整数倍;所以
sizeof(struct stu)会等于12;
2.为什么要进行内存对齐?
2.1平台原因:
某些平台需要数据出现在特定的位置处;
2.2性能原因:
实际上就是一个空间换取时间的过程,32位的机器,一次就读取4个字节(32个bit),当你将结构体中的数据连续存放时,会出现 char int int int | int这种情况,需要重新再读取一遍前面的三个int,会降低性能,但是对齐的话,可以直接跳过,就能刚好读到起始的位置;
在上面的两个例子中可以得知,第二种浪费的空间就会比较多;所以,为了节省空间,我们在定义结构体的时候应该尽量让占空间小的变量集中在一起。
3.修改默认对齐数:
#pramga pack()想改多少就填多少
4.结构体的位段
注意的事项:
1.位段的成员必须是char(整型) int unsigned int或者signed int
2.位段是不跨平台的
struct stu {
int a:2;
int b:5;
int c:10;
int d:30;
};
冒号后面的代表需要多少个比特位;
4.1
位段的内存存放方式(vs x86环境下):
一开始先在01地址(假设)处生成一个int类型的的空间,首先分配2个比特的空间给a,再分配5个比特给b,接着再分配10个比特给c,现在就占了32个比特位中的17个比特了,已经放不下d的了,所以需要浪费这部分空间,在05地址处再生成一个新的int空间,同理分配30个空间;
4.2
对不跨平台原因进行部分探究:
1.int在不进行位段的时候不会考虑有无符号整型(char正常也需要考虑),正常就是signed,但是在跨平台的时候就需要考虑这个问题;
2.不同平台对类型的字节设置是不同的;
3.位段中的成员在内存中是左到右还是右到左是不确定的;
4.位段在上面那个例子中int大于了剩余空间,是否会进行消耗,也是不确定的。