Los expertos en ensamblaje hablan sobre cómo funciona la CPU detrás de la alineación de la memoria
Alineación de la memoria:
Sabemos que en los sistemas informáticos modernos, la CPU accede a la memoria según palabras dobles, palabras y bytes y los transmite a través del bus si no hay certeza. reglas de alineación, las operaciones de acceso a la CPU y las operaciones de transferencia de bus serán extremadamente complejas, por lo que los compiladores modernos alinearán automáticamente la memoria.
1. Coeficiente de alineación de la memoria
Cuando se trata de alineación de la memoria, tenemos que hablar del coeficiente de alineación de la memoria. La forma más sencilla de establecer el coeficiente de alineación es configurarlo con #. pragma pack (n). Haga clic en el enlace para presentar esta parte del contenido en detalle en mi artículo.
2.sizeof
Cuando se trata de alineación de memoria, lo segundo que tengo que decir es sizeof, que básicamente determina el tipo de datos o la longitud de la expresión que necesitas. a prestar atención Sí, esto no es una función, ¡sino una palabra clave en C++! El cálculo del número de bytes se realiza cuando se compila el programa, no cuando se ejecuta.
3. La longitud del tipo y la alineación de los miembros de datos
En su computadora, la longitud del tipo de datos se refiere al uso de sizeof en el tipo de datos en su computadora. Por supuesto, los resultados obtenidos en varios entornos de compilación también son diferentes.
Por ejemplo, en un entorno Visual Studio de 32 bits:
cout << sizeof(char) << endl ?// 1
cout < < tamaño de (corto) << endl;// 2
cout << tamaño de (int) << endl;// 4
cout << tamaño de (largo) < < endl ?// 4
cout << sizeof(double) << endl ?// 8
En el entorno de compilación de G++ de 64 bits:
cout << tamaño de (char) << endl;// 1
cout << tamaño de (corto) << endl ?// 2
cout << tamaño de (int) << endl;// 4
cout << tamaño de (largo) << endl;// 8
cout << tamaño de (doble) << endl; ? // 8
A continuación explicaré la alineación de los miembros de datos en el entorno de Visual Studio de 32 bits:
Primero que nada, debemos dejar claro que los miembros de las estructuras se asignan de forma contigua en la memoria, la primera dirección de la estructura también es la dirección del primer miembro de datos de la estructura. En otras palabras, el primer miembro de datos de la estructura está a cierta distancia de la posición inicial de la estructura.
La regla para la alineación de miembros de datos es que después del primer miembro, el desplazamiento de la primera dirección de cada miembro de la estructura está relacionado con la longitud (tamaño de) del propio miembro de la estructura.
Si esta regla no se cumple cuando no está alineado, se rellenará un segmento vacío delante del miembro cuando esté alineado, llevándolo a un estado de miembro de datos alineado.
Cuando el n predeterminado es 8:
struct {
char a;
double b;
} myStruct;
cout << tamaño de myStruct << endl;// 16
cout << (int *)&myStruct.a << endl; p>
cout << &myStruct.b << endl;// 0024F8A0 (varía según el tiempo de ejecución)
Cuando n se establece en 4, es decir, min(sizeof(double), n) = 4:
#pragma pack(4)
struct {
char a;
doble b;
} miEstructura;
cout << tamaño de miEstructura << endl;// 12
cout << (int *)&myStruct.a << endl;
cout << &myStruct.b << endl;// 0046F770
Para el primer ejemplo, el valor mínimo es 8, con 7 bytes rellenados después del carácter a.
Para el segundo ejemplo, el valor mínimo es 4, que rellena 3 bytes después del carácter a.
4. Alineación general
El compilador realiza una alineación general después de la alineación de los miembros de datos. Similar pero no exactamente igual a la alineación de datos, si el tamaño de la estructura después de completar la alineación de datos no es la longitud de los miembros de la estructura (sizeof) y después de completar la alineación de datos, el tamaño de la estructura no es el valor máximo. de la longitud de los propios miembros de la estructura (sizeof) y un múltiplo entero del valor mínimo de n en #pragma pack(n). (Tenga en cuenta que esto se refiere al que tiene la longitud de miembro más grande en comparación con n, no al específico). Simplemente agregue bytes nulos al final de la estructura hasta que esté alineada.
Cuando n se establece en 4, es decir, min(sizeof(short), n) = 2:
#pragma pack(4)
struct {
char a;
b corta;
char c;
} myStruct;
cout < < tamaño de miEstructura << endl;// 6
cout << (int *)&myStruct.a << endl;// 003DFED0
cout << &myStruct.b < < endl ?// 003DFED2
cout << (int *)&myStruct.c << endl ?// 003DFED4
En el ejemplo anterior, debido a la alineación de miembros, char a El desplazamiento es 0, ocupa [D0] relleno [D1] **** dos bytes cortos; b es el miembro de longitud máxima, no alineado, ocupa [D2-D3] dos bytes, y su desplazamiento es 2; char c es 4 y ocupa [D4]. No hay alineación de miembros, pero el tamaño de la estructura en este momento es 2 + 2 + 1 = 5 bytes, que no es un múltiplo entero de 2, por lo que debemos completarlo en al final Vacíe las subpartes hasta que el tamaño de la estructura alcance un múltiplo entero de 2, que es la alineación general.
Una vez completadas la alineación de los miembros de datos y la alineación general de la memoria, si piensa en las reglas anteriores, encontrará que incluso si el número de miembros de datos es el mismo y el orden de ubicación es diferente, el El tamaño de la estructura será diferente. Aquí hay un ejemplo:
Esto es 12 bytes:
12 bytes.png