Problema de alineación de memoria en lenguaje C

Razones para la alineación de la memoria

Sabemos que la unidad más pequeña de memoria es un byte, y la CPU lee datos de la memoria en bloques, y el tamaño del bloque es 2 elevado a n.

La alineación de la memoria es la estrategia del sistema operativo para mejorar el acceso a la memoria. Al acceder a la memoria, se lee una longitud determinada cada vez (esta longitud es el número de alineación predeterminado del sistema operativo, o un múltiplo entero del número de alineación predeterminado). Si hay sin alineación, para acceder a una variable se puede acceder dos veces.

Como en la figura anterior, cada unidad es un byte y char ocupa un byte. Si desea poner un dato de tipo int debajo, ¿dónde debería ponerlo?

Si coloca de la dirección 1 a la dirección 4, en este caso, agregue un tamaño de bloque de 4 bytes. Para eliminar estos datos, debe eliminar el primer bloque y el segundo bloque. Tome los últimos tres bytes del primer bloque y el segundo bloque Se empalma el primer byte. Necesita acceder a la memoria por segunda vez.

Ponga los datos int al principio de la dirección 4. La idea de intercambiar espacio por tiempo.

¿Cómo alinear la memoria?

Para los tipos de datos estándar, su dirección solo necesita ser un múltiplo entero de su longitud.

Para tipos de datos no estándar, como estructuras, se deben seguir los siguientes principios de alineación:

1. Reglas de alineación de miembros de la matriz, el primer miembro de la matriz debe colocarse donde el desplazamiento es 0, y cada miembro de la matriz en el futuro debe colocarse donde el desplazamiento es un múltiplo entero de min (el tamaño del miembro actual, #pargama pack (n)) (Por ejemplo, int es 4 bytes en una máquina de 32 bits, #pargama pack (2), luego comience a almacenar en un múltiplo de 2)

2. El tamaño total de la estructura, que es el resultado de sizeof, debe ser un múltiplo entero de min (el miembro más grande de la estructura, #pargama pack (n)), que no es suficiente para estar alineado

3. Las estructuras son las reglas de alineación para los miembros. Si una estructura B está anidada en otra estructura A, todavía está alineada con el tamaño del tipo de miembro más grande, pero el punto de partida de la estructura A es un múltiplo entero del miembro más grande en un. (Hay una estructura A en la estructura B, y hay miembros como char, int y double en A. Entonces A debe almacenarse a partir de un múltiplo entero de B.), las reglas de alineación de los miembros en la estructura A aún satisfacen el principio 1, principio 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;
}

tamaño de = 24
Por favor presione cualquier tecla para continuar ...

En primer lugar, ¿por qué es 24? ¿Cuál es la relación del módulo de alineación?

Agregamos #pragma pack (show) al código y luego no es necesario volver a ejecutar el código, solo regenerarlo, puede ver la relación del módulo de alineación

Puede ver que la relación de módulo de alineación predeterminada es 8. De acuerdo con la regla, según el tercer artículo, el todo debe colocarse en un múltiplo entero de min {8,8} = 8, 20 no lo es, por lo que es 24

El módulo de alineación se puede cambiar, se puede cambiar a la enésima potencia de 2, por ejemplo

Cambie a #pragma pack (1), el resultado de la ejecución se muestra como 17. De esta manera, no hay alineación en absoluto, y todos los datos están encantados.  

Cuando la estructura está anidada:

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

resultado de la operación:

tamaño de = 24
tamaño de = 40
Pulse cualquier tecla para continuar ...

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_42596333/article/details/104510460
Recomendado
Clasificación