Q1:什么是偏移量?linux
A:结构体变量中成员的地址和结构体变量地址之差。能够用offsetof(type, member)宏来肯定成员的实际位置(定义于stddef.h),其中type是结构体类型,member是成员名。可知:第一个成员的偏移量为0,最后一个成员的偏移量加上最后一个成员的大小却不必定等于结构体大小(先卖个关子=。。=)。windows
Q2:什么是地址对齐?数组
A:结构体成员是按照声明的顺序存储在连续的内存空间中,而结构体成员的类型不必定相同,系统在存储结构体时不是像数组同样将各个成员大小简单相加,而须要考虑地址对齐问题。测试
先来简单看一个例子:spa
Q3:上述两种形式的结构体大小是否相同?blog
A:不相等,虽然结构体成员相同,可是因为声明顺序不一样致使地址偏移量不一样。具体而言第一个结构体大小为16,第二个为24。ip
Q4:结构体存储时地址对齐,编译器须要遵循什么原则?内存
A:两条原则:编译器
1.结构体变量中成员的偏移量必须是成员大小的整数倍;编译
2.结构体大小必须是全部成员大小的整数倍,即全部成员大小的公倍数。
对照上述两条原则,回过来看上述两个结构体大小是否是清楚明白了?Student1很好理解,Student2中scores成员偏移量为16,加上自身大小4后为20,因为20不是8的整数倍,去最小公倍数24为整个结构体大小。(最后一个成员的偏移量加上最后一个成员的大小却不必定等于结构体大小=。。=)
-------------------------------------------我是一条可爱的分割线-------------------------------------------------------
增长点难度,再来看一个例子:
你们思考一下结构体Student3的大小?结构体ss偏移量?结构体ss大小为8,若是将ss看成一个总体Student3大小是否是24?
测试结果倒是:
Q5:出现结构体嵌套时,怎么计算结构体大小?
A:上述两个原则须要修改一下:
1.展开后的结构体的第一个成员的偏移量(嵌套的结构体偏移量)应当是被展开的结构体中最大成员的整数倍;
2.结构体大小必须是全部成员大小的整数倍,这里计算的是展开后的成员,而不是将嵌套的结构体看做一个总体。
总结与反思:了解结构体存储方式后,咱们该怎么作才能充分利用内存,减小边界对齐带来的空间损失?
1.重排结构体成员声明列表,让那些对边界要求最严格(大)的成员首先出现,对边界要求最弱(小)的成员最后出现;
2.在考虑程序的可读性和可维护性的前提下,能够把相关联的成员放在一块儿而不用考虑列表顺序问题,不然参考1;
3.在程序声明几百个甚至几千个结构体时,减小内存的浪费要比程序的可读性更为急迫,这时能够经过增长注释来提升可读性。
tip:如何给结构体变量分配空间由编译器决定,以上代码均在linux/GCC下编译,windows/VC也是如此,其余平台可能有不一样的处理方式。