为什么需要数据对齐?
避免数据在内存中跨边界存储,减少读取数据次数,提高效率,本质上是以空间换时间的做法
下图中属于同一水平位置的为同一边界
变量在同一边界里的一次存储周期就可以读取
一旦跨了上下两个边界来存储就需要至少两个存储周期来读取
根据存储器结构,如下图,参考链接:多体并行:高位/低位交叉编址
CPU数据线有32位一次最多可以从内存读取32数据,这里的一次指一次存储周期
LDR r1 , [pc,#4], 是从pc+#4地址处开始连续读取4个字节的数据到r1寄存器
LDRH r1 , [pc,#4], 是从pc+#4地址处开始连续读取2个字节的数据到r1寄存器
LDRB r1 , [pc,#4] 直接取pc+#4当前那个地址的数据
上述指令都是在一个存储周期里完成的
一般地址线只能确定一个字节所在的地址,而上述指令地址都一样,却不止读到仅仅一个字节的数据,还能读到2个字节或者4个字节的数据,可以看到上述指令除了操作码不一样其它都一样,按照上图的存储结构,指令的地址一样那么体内地址肯定是一样的,体内地址一样就横向选中了同一水平位置的存储,操作码的不同说明控制线输出的信号应该不同,就可以控制一个类似体号的控制器,选中连续的好几个字节的存储
地址线加上控制线就可以实现上述的操作
LDM r1 ,{r0-r1} ; 是将r1指向的内存地址开始连续8个字节的数据存放到r0和r1寄存器中
该指令是在2个存储周期里完成的
对于数据在内存中的位置,需要确定两个因素:大小、起始位置
根据存储器结构,就是通过起始位置和数据大小获取内存中的数据
一、全局变量静态变量,地址从小增大
1、原子类型数据
按照开始的存储结构的图,short型变量起始位置放在地址1的位置应该也放得下,也能一次性读取,为什么必须得是0,2,4,6.。。。
那是因为放在不好判断地址1和地址3的不同,放在地址3就会跨界,而为了区分地址1和3做出来的电路更为复杂得不偿失,
8字节的也是同理
2、组合类型数据
详细参考链接:
详解边界对齐
// structure C
typedef struct structc_tag
{
char c;
double d;
int s;
} structc_t;
这个结构的大小应该是 sizeof(char) + 7 + sizeof(double) + sizeof(int) = 1 +7 + 8 + 4 = 20
然而,正确答案是24
所以,所有结构的起始存储位置必须是结构中对边界要求最严格的数据类型所要求的位置。
struct {
int a;
short b;
int c;
char d;
}A;
struct {
double a;
short b;
int c;
char d;
}B;
上述总结还有另一个表达,组合数据结构的大小是组合结构中最大原子数据大小的整数倍:上述结构B就是20不是8的整数倍,24是8的整数倍
总结:
第一,编译器按照成员列表的顺序给每个成员分配内存.
第二,当成员需要满足正确的边界对齐时,成员之间用额外字节填充.
第三,结构体的首地址必须满足结构体中边界要求最为严格的数据类型所要求的地址. (也即首地址为最宽基本类型的整数倍)
第四,结构体的大小为其最宽基本类型的整数倍.
3、#pragma pack (2)的作用
详细参考链接:为什么要内存对齐?字节对齐和边界对齐介绍。
文章中说的编译器默认4字节对齐是错误的,默认是8字节对齐其它分析都对
这里的指定几字节对齐,意思是数据本身的对齐数大于指定的话就按指定的对齐数来,也就是数据起始地址为指定对齐数的倍数
下面的struct中int a的自身对齐数为4大于指定对齐数2,所以按照2来,它存放的起始地址就为0,2,4,6.。。。这些
4、结构体中嵌套结构体
#pragma pack(8)
struct example1 {
short a;
long b;
};
struct example2 {
char c;
struct example1 e;
short s;
};
struct example2数据结构的大小是16个字节,这个值是这样计算出来的:
1(char c) + 3(padding) + 8(struct example1 e) + 2(short s) + 2(padding) = 16。
该类型也是按照组合类型数据的规则来计算大小
二、局部变量,栈中的变量
不同的数据(或数据结构)按顺序从地址大处向地址低处,同一数据内按顺序地址从小到大
sp要8字节对齐,sp的地址只会是8的倍数,(现象就是每次压栈出栈都是8的倍数个,参考下面的)
栈中的数据与全局数据相同的是大小的计算方法一样,不同的是栈中的数据起始地址不是自身对齐值的倍数而是4的倍数或8的倍数(如果自身对齐值小于4就是4的倍数大于4就是8的倍数)
1、结构体变量加lr寄存器大小小于8字节
typedef struct
{
char a;
char b;
} Tchar;
void temp()
{
Tchar a2 = {
'!','s'};
a2.a = a2.a + a2.b;
printf("the size of struct Tchar is %d\r\n ",sizeof(a2));
printf("the address of struct Tchar is %p\r\n ",&a2);
printf("the address of struct Tchar a is %p\r\n ",&a2.a);
printf("the address of struct Tchar b is %p\r\n ",