C语言内存对齐问题

内存对齐的原因

我们知道内存的最小单元是一个字节,CPU从内存中读取数据是以块为单位的,块的大小为2的n次方。

内存对齐是操作系统为了提高访问内存的策略,在访问内存的时候,每次读取一定长度(这个长度是操作系统默认的对齐数,或者默认对齐数的整数倍),如果没有对齐,为了访问一个变量可能产生二次访问。

像上图中每个单元为一个字节,char占了一个字节,如果下面要放一个int型数据,该放在哪呢?

如果从1地址放到4地址,那这样的话,加入块大小为4字节要取出这个数据需要把第一块和第二块取出,取第一块的后面三个字节和第二块的第一个字节拼接。需要二次访问内存。

把int型数据放到4地址开头。以空间换时间的思想。

如何内存对齐?

对于标准数据类型,它的地址只要是它的长度的整数倍。

对于非标准数据类型,比如结构体,需遵循以下对齐原则:

1.数组成员对齐规则,第一个数组成员应该放在offset为0的地方,以后每个数组成员应该放在offset为min(当前成员的大小,#pargama pack(n))整数倍的地方开始(比如int 在32位机器为4字节,#pargama pack(2),那么从2的倍数地方开始存储)

2.结构体总的大小,也就是sizeof的结果,必须是min(结构体内部最大成员,#pargama pack(n))的整数倍,不足要对齐

3.结构体作为成员的对齐规则,如果一个结构体B里嵌套另一个结构体A还是以最大成员类型的大小对齐,但是结构体A的起点为A内部最大成员的整数倍的地方。(struct B里存有struct A,A里有char,int ,double等成员,那A应该从B的整数倍开始存储。),结构体A中的成员的对齐规则仍满足原则1、原则2.

#include<stdio.h>
#include<stddef.h>
#pragma pack(show)  //查看对齐模数,默认为8
//#pragma pack(1)

//对于自定义数据类型,内存对齐规则如下;
//1.从第一个属性开始,偏移为0
//2.第二个属性开始,地址要放在  该类型整数倍  与  对齐模数比   取小的值  的整数倍上
//3.所有的属性都计算结束后,整体再做二次对齐,整体需要放在属性中 最大类型 与 对齐模数比 取小的值 的整数倍上
typedef struct _STUDENT{

	int a;    //0~3
	char b;   //4~7
	double c; //8~15 
	float d;  //16~19
}Student;

void test01()
{
	printf("size of = %d\n",sizeof(Student));
}



int main()
{
	test01();
	
	return 0;
}

size of = 24
请按任意键继续. . .

首先为什么是24呢?对齐模数比是什么呢?

我们在代码中加入 #pragma pack(show) 然后不用重新运行代码,只需要重新生成,就可以看到对齐模数比是多少了

可以看到默认对齐模数比为8,按照规则,根据第三条,整体应放在min{8,8} = 8 的整数倍上,20不是,所以是24

对齐模数是可以改的,可以改为2 的 n 次方,例如

改为#pragma pack(1),运行结果显示为17.这样根本就没有对齐了,数据都是爱着放的  

当结构体嵌套结构体时:

#include<stdio.h>
#include<stddef.h>
#pragma pack(show)

//对于自定义数据类型,内存对齐规则如下;
//1.从第一个属性开始,偏移为0
//2.第二个属性开始,地址要放在  该类型整数倍  与  对齐模数比   取小的值  的整数倍上
//3.所有的属性都计算结束后,整体再做二次对齐,整体需要放在属性中 最大类型 与 对齐模数比 取小的值 的整数倍上
typedef struct _STUDENT{

	int a;    //0~3
	char b;   //4~7
	double c; //8~15 
	float d;  //16~19
}Student;

//结构体嵌套结构体时,首先Student b 放在 Student中最大数据类型的整数倍上就可以,所以8,它的size为24,所以0~7,8~31,32~39
//然后二次对齐,这时候他不是看Student类型最大size,而是看Student中最大类型,为8,所以40是8的倍数,不用再对齐
typedef struct _STUDENT2{

	int a;    //0~7
	Student b;   //8~31
	double c; //32~39 
}Student2;

void test01()
{
	printf("size of = %d\n",sizeof(Student));
}
void test02()
{
	printf("size of = %d\n",sizeof(Student2));
}



int main()
{
	test01();
	test02();
	return 0;
}

运行结果:

size of = 24
size of = 40
请按任意键继续. . .

猜你喜欢

转载自blog.csdn.net/weixin_42596333/article/details/104510460