在嵌入式底层开发中经常会遇到内存对齐的问题,整理一下吧:
1. 内存对齐的概念
对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的。
2. 内存对齐的原因
需要内存对齐的根本原因在于CPU访问数据的效率问题。
假设整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误。
3. 内存对齐在结构体的典型应用
运算符sizeof 可以计算出给定类型的大小,对于32位系统来说,sizeof(char) = 1; sizeof(int) = 4。
基本数据类型的大小很好计算,下面看下如何计算构造数据类型的大小。
C语言中的构造数据类型有三种: 数组、结构体和共用体。
结构体中的成员可以是不同的数据类型,成员按照定义时的顺序依次存储在连续的内存空间。和数组不一样的是,结构体的大小并不是所有成员大小简单的相加,需要考虑到系统在存储结构体变量时的地址对齐问题。
看下面的结构体:
struct stu1 {
int i;
char c;
int j;
}
掌握以下计算结构体变量必需的概念:
- 偏移量
结构体成员的第一个成员偏移量是0,后面成员的偏移量等于上一个成员的偏移量+上一个成员变量的大小。
结构体类型的大小计算必须满足的两个条件:
- 结构体变量成员的偏移量必须能够整除此成员变量
- 结构体类型的大小必须能够整除结构体的任何任何一个成员变量的大小
如果上面两个条件不成立的话就需要在成员变量之间填充字节,使之成立。
回过头来算一下上面那个结构体类型的size,
i 的偏移量是0, 认为0可以整除所有的数,
c 的偏移量是4,可以整除1,
j 的偏移量是5, j 的大小是4,这样就需要在c 后面的内存中填充3个字节,使之满足整除4,
这样算下来此结构体的大小是8+4=12,验证一下能够整除所有的成员变量,所以结论成立大小就是12.
在VC 写个测试代码看看:
#include <stdio.h>
#include <stdlib.h>
struct stu1 {
int i;
char c;
int j;
};
struct stu1 student;
void main()
{
int addr = 0;
student.i = 0xAAAAAAAA;
student.c = 0xBB;
student.j = 0xCCCCCCCC;
addr = &student;
printf("The size of the struct is %d\n",sizeof(struct stu1));
}
参考文章: