边界对齐与读写周期
一、边界对齐原则
一句话:K字节大小的数据必须要存储在K的整数倍的地址上
例如:一个存储字长为32位的机器,依次存入一个int,short,double,char,short类型的数据的过程。假定int ,short,double ,char分别为4,2,8,1字节。那么它们分别占据字、半字、双字、字节。
字地址:4字节的倍数,半字地址:2字节的倍数,双字地址:8字节的倍数,字节地址:任意
①第一个int就正好占据一个字,第一行就全是int。
②short是半字,地址要是2的倍数,随意要占据第二行的前两格。
③double是双字,地址要是8的倍数,第三行第一个正好是8,所以占据3,4两行。
④char是字节,任意,所以占据double后面的一个格子就行了,这里正好是第五行的第一格。
⑤short是半字,地址要是2的倍数,而char后面的那个地址是17,所以short的首地址不可以正好在char后面,要空一格,从18开始的两个格子。
边界对齐后插入数的位置如图所示:
二、结构体边界对齐
结构体计算遵循边界对齐的原则:
1.结构体变量的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍。(对齐)
2.结构体变量中的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节的整数倍。(对齐)
3.结构体变量的总大小,为结构体变量中“最大基本数据类型成员所占字节数”的整数倍(补齐)
例如:机器字长32位,分析下面两个结构体的存储空间。如果依次读取两个结构体中的各个元素,各需要多少次读写周期。
struct test {
char x1;
int x2;
short x3;
long x4;
}__attribute__((packed));
struct test2 {
char x1;
int x2;
short x3;
long x4;
};
test结构体加上__attribute__((packed))表示取消边界对齐,结构体的大小等于每个变量的大小之
和。test1则要遵循边界对齐。
三、读写周期
一个读写周期读取的字长等于机器字长,从内存的起始位置开始,每次读一个机器字长的内容,依次往下,直到读完需要的全部数据,读取次数就是读写周期数。
如果该变量的起始位置不是机器字长的整数倍,且占有了机器字长整数倍的位置,那么就需要读至少两次。
本题中,机器字长为4个字节,则一次读一行。
test:
首地址 | 0字节 | 1字节 | 2直接 | 3字节 |
0 | x1 | x2 | x2 | x2 |
4 | x2 | x3 | x3 | x4 |
8 | x4 | x4 | x4 |
test大小为11字节。
读取x1要1个读写周期,读取x2要两个读写周期,读取x3一个读写周期,读取x4两个读写周期,故读取test需要6个读写周期。
test1:
首地址 | 0字节 | 1字节 | 2直接 | 3字节 |
0 | x1 | |||
4 | x2 | x2 | x2 | x2 |
8 | x3 | x3 | ||
12 | x4 | x4 | x4 | x4 |
test1大小为16字节。
读取x1一个读写周期,读取x2一个读写周期,读取x3一个读写周期,读取x4一个读写周期,故读取test1需要4个读写周期。