C language memory alignment problem

Reasons for memory alignment

We know that the smallest unit of memory is a byte, and the CPU reads data from memory in blocks, and the block size is 2 to the power of n.

Memory alignment is the operating system's strategy to improve memory access. When accessing memory, a certain length is read each time (this length is the default alignment number of the operating system, or an integer multiple of the default alignment number). If there is no alignment, in order to access A variable may be accessed twice.

As in the figure above, each unit is one byte, and char occupies one byte. If you want to put an int type data below, where should you put it?

If you put from address 1 to address 4, in this case, add a block size of 4 bytes. To take out this data, you need to take the first block and the second block, take the last three bytes of the first block and the second block The first byte is spliced. Need to access the memory a second time.

Put int data at the beginning of address 4. The idea of ​​trading space for time.

How to memory alignment?

For standard data types, its address only needs to be an integer multiple of its length.

For non-standard data types, such as structures, the following alignment principles should be followed:

1. Array member alignment rules, the first array member should be placed where the offset is 0, and each array member in the future should be placed where the offset is an integer multiple of min (the size of the current member, #pargama pack(n)) (For example, int is 4 bytes on a 32-bit machine, #pargama pack(2), then start storing at a multiple of 2)

2. The total size of the structure, which is the result of sizeof, must be an integer multiple of min (the largest member in the structure, #pargama pack(n)), which is not enough to be aligned

3. Structures are the alignment rules for members. If a structure B is nested in another structure A, it is still aligned with the size of the largest member type, but the starting point of the structure A is an integer multiple of the largest member in A. (There are struct A in struct B, and there are members such as char, int and double in A. Then A should be stored from an integer multiple of B.), the alignment rules of members in structure A still satisfy principle 1, principle 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
Please press any key to continue...

First of all, why is it 24? What is the alignment modulus ratio?

We add #pragma pack(show) to the code and then do not need to re-run the code, just regenerate it, you can see the alignment modulus ratio

It can be seen that the default alignment modulus ratio is 8. According to the rule, according to the third article, the whole should be placed on an integer multiple of min{8,8} = 8, 20 is not, so it is 24

The alignment modulus can be changed, it can be changed to the nth power of 2, for example

Change to #pragma pack(1), the running result is displayed as 17. This way there is no alignment at all, and the data are all put in love  

When the structure is nested:

#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;
}

operation result:

size of = 24
size of = 40
Please press any key to continue...

 

 

Guess you like

Origin blog.csdn.net/weixin_42596333/article/details/104510460