内存对齐
一、结构体
首先在C语言中,结构体占用的是一片连续的内存空间
对齐原因
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
以前对于内存对齐的计算理解错了,今天看见一个视频幡然醒悟。
以下面的结构体为例:
struct stu
{
char *p; //4
char arr[2]; //2 → 4+2+2(补)=8
int c; //4
short d; //2 → 4+2+2(补)=8
double f; //8
long g; //4 → 4+4(下面 float h[2] 中取一个刚好可以凑足 8 个字节)=8
float h[2]; // 4(上面拿走了一个)+4(补)=8
}stu;
内存对齐规则:以结构体中占用字节数最大的修饰变量的关键字为基准进行对齐。
在 stu 中(32位操作系统):首先占用内存最大的关键字为 double 占 8 个字节。
以此为基准对齐,从头开始看。指针 p 占四个字节,arr 占 1*2 = 2个字节,共 6 个字节,不足 8 位,c 占4个字节,如果接着加上前面的就超出了 8 字节的基准,所以 先对前面的 6 个字节进行补齐(6+2 = 8),再看 c 的下一个 d 占2个字节,同样的 4+2 = 6 未超出 8,所以看 double f,超出了,所以前面的 c 和 d占用字节为(4+2 = 6 → 6+2 = 8);f 刚好 8 个字节;继续看 g,占用 4 个字节,不足 8 ,因为 h是个含两个 float 类型的数组,一个 float 刚好占四个字节,所以拿一个与前面的 g 相加,最后只剩一个 float 类型的数据,占 4 个字节,不足 8,所以补 4.(4+4 = 8);
所以: 4(char *p)+ 2(char arr[2])+ 2(补)= 8;
4(int c) + 2(short d)+ 2(补)= 8;
8(double)
4(long g)+ 4(float h[1])= 8;
4(float h[1])+ 4(补) = 8;
共占 40个字节。
2、结构体嵌套
struct stra
{
int a; //4
float b; //4
char c; //1 → 1 + (3) = 4
} //共计 12 个字节
struct strb
{
double d; //8
char * e; //4
short f; //2 → 4+2+(1) = 8
struct atra abc; //以外层结构体的 8 字节对齐 → 4(int)+ 4(float)= 8;1(char)+ 7(补) = 8;共计 16个字节
} //共计 32 个字节
二、共用体
共用体只有最后一次被赋值的值是准确的。
共用体的成员公用一片内存空间。其所占内存空间大小为成员中数据类型所占空间最大的空间的整数倍。
例:
union vars
{
double a; //8
float b; //4
int c; //4
short d; //2
char f; //1
char arr[12]; //12
} //共计16个字节
其中最大的数据类型为 double,占 8 个字节的内存空间,所以以 8 字节对齐,联合体中占内存空间最大的为数组 char arr[12],共 12个字节大小,但要以 8 字节对齐所以,联合体共占 16个字节