注:所有实验没有说明都是以四字节对齐方式对齐,起始地址强制转换为0x0000 0000
1.结构体对齐:
通过调试代码,可以发现计算机存在内存对齐,看结构体的每个内部数据的地址可以发现:**p->dd的地址为0x0000 0008,如果不存在内存对齐,p->ee的起始地址应该为0x0000 0009,而实际上它的起始地址为0x0000 000c,明显闲置了三个字节。**
对于求一个结构体的大小而言(四字节对齐):
(1) 当它是的内部数据成员为一个char类型时,你应该放心的在原有的大小上面加上一个字节;
(2)当它的内部数据成员所占字节为两个时,比如short等,你看一下它的地址的起始位置是不是偶数地址,是偶数地址,放心的加上两个字节大小,(上例中p->bb的地址为偶数地址,直接在原来的大小4个字节的基础上加上2个字节,为6个字节大小)不是偶数地址,空开一个字节来到偶数地址,在原有的大小上加上两个字节大小(上例中p->dd的地址如果不存在内存对齐则为奇数地址,这个时候应该直接空开一个字节,它的起始地址就为0x0000 0008,然后再在这个地址的基础上加上short所占字节大小,所以此结构体的所占字节数来到十个字节);
(3) 当它的内部数据成员所占字节为四个字节时,比如int等,这时候应该看一下它的地址起始位置能不能被4整除,(上例中p->ff如果不存在内存对齐它的起始地址为0x0000 000b 显然它的地址不能被4整除,所以空开一个字节,来到地址0x 0000 000c显然它的地址是能被4整除,所以在这个地址的基础上加上int所占字节大小,所以结构体的大小来到十六个字节);根据调试结果显然此结构体的大小为16个字节。
总而言之:求一个对齐数为四个字节的结构体大小时,把每四个字节化为一组,单字节类型数据只要这一组还有一个字节的空位就可以放(不能为前面的数据类型对齐留下的空格);双字节类型只要这一组还有三个字节或三个字节空位以上就一定能够放,当有两个字节空位时,必须要看它的起始地址能否被2整除;四字节类型必须要有四个字节的空位存放在一组。
2.联合体对齐
对齐原则:就是使得对齐尺寸要求最大的数据类型得以满足,并且对齐数为对齐方式的整数倍。
显然联合体中的最大数据类型为结构体结构体的大小为十六个字节,而对齐方式为四字节对齐,对齐数显然为对齐方式的整数倍。
3.位段(位域)对齐
位域对齐原则:
(1)如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
(2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其 偏移量为其类型大小的整数倍;
4.为什么要内存对齐:
平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。