Red de conocimientos turísticos - Conocimientos sobre calendario chino - ¿Quién puede explicarme el concepto de alineación de bytes en las operaciones de lectura y escritura del microcontrolador SPI FLASH?

¿Quién puede explicarme el concepto de alineación de bytes en las operaciones de lectura y escritura del microcontrolador SPI FLASH?

El espacio de almacenamiento de las computadoras modernas está dividido por bytes. En teoría, parece que cualquier tipo de acceso a variables puede comenzar desde cualquier dirección, pero la situación real es que cuando se accede a un tipo específico de variable, a menudo se accede a una dirección de almacenamiento específica. Requiere que varios tipos de datos se organicen secuencialmente en el espacio de acuerdo con ciertas reglas, en lugar de uno tras otro. Esto es alineación. Qué hace la alineación y por qué: cada plataforma de hardware maneja el espacio de almacenamiento de manera muy diferente. Algunas plataformas solo pueden acceder a ciertos tipos de datos desde determinadas direcciones. Por ejemplo, algunas arquitecturas de CPU producirán errores al acceder a variables no alineadas, por lo que la programación en dichas arquitecturas debe garantizar la alineación de bytes. Puede que este no sea el caso en otras plataformas, pero a menudo hay una pérdida en la eficiencia del acceso si el almacén de datos no está alineado según lo requiere la plataforma. Por ejemplo, algunas plataformas leen datos desde el principio de la dirección par cada vez. Si se almacena un tipo int (suponiendo un sistema de 32 bits) al principio de la dirección par, entonces los datos de 32 bits se pueden leer en uno. ciclo de lectura, y si el almacenamiento al comienzo de una dirección impar requiere dos ciclos de lectura y unir los resultados de dos lecturas de los bytes superior e inferior para obtener datos de 32 bits. Obviamente, esto reducirá en gran medida la eficiencia de lectura.

II. El impacto de la alineación de bytes en los programas:

Veamos algunos ejemplos (32 bits, entorno x86, compilador gcc):

Configuración Una estructura es la siguiente:

Estructura A

{

int a;

char b;

short c ;

Esta es la primera vez que leemos un archivo de datos de 32 bits.

};

Estructura B

{

char b;

int a;

short c;

};

Las longitudes actualmente conocidas de varios tipos de datos disponibles en máquinas de 32 bits son las siguientes:

char: 1 (Firmado y sin firmar son lo mismo)

short:2 (firmado y sin firmar)

int:4 (firmado y sin firmar)

long :4 (firmado y unsigned)

float:4 double:8

Entonces, ¿cuáles son los tamaños de las dos estructuras anteriores?

El resultado es:

sizeof(strcut A) es 8

sizeof(struct B) es 12

La estructura A contiene un 4 bytes int, un carácter de 1 byte y un corto de 2 bytes. La estructura B debe tener un tamaño de 7 bytes.

La razón de los resultados anteriores es que el compilador debe realizar una alineación espacial en los miembros de datos. Lo anterior es el resultado de la alineación de acuerdo con la configuración predeterminada del compilador. Por supuesto, no podemos cambiar la configuración de alineación predeterminada del compilador en este momento. Por ejemplo:

#pragma pack (2)

struct C

{

char b;

int a;

short c;

};

#pragma pack ()

El valor de sizeof (struct C) es 8.

Cambie el valor de alineación a 1:

#pragma pack (1)

struct D

{

char b;

int a;

short c;

};

# pragma pack ()

El valor de sizeof(struct D) es 7.

Explicaremos la función de #pragma pack() más adelante.

III. ¿Cuáles son los principios de alineación del compilador?

Primero, veamos cuatro conceptos básicos importantes:

1. La alineación del tipo de datos en sí:

Para datos de tipo char, su propia alineación el valor de es 1; para datos de tipo corto, su propio valor de alineación es 2; para datos de tipo int, flotante, doble, su propio valor de alineación es 4, en bytes.

2. El valor de autoalineación de una estructura o clase: el valor con mayor valor de autoalineación entre sus miembros.

3. Valor de alineación especificado: Valor de alineación especificado en el paquete #pragma (valor).

4. Valores de alineación válidos para miembros, estructuras y clases de datos: el valor más pequeño entre el valor de autoalineación y el valor de alineación especificado.

Utilizando estos valores, es fácil discutir la alineación de los miembros de una estructura de datos particular consigo misma. El valor de alineación efectiva, N, es el valor final y más importante utilizado para determinar cómo se abordan los datos. Un valor de alineación válido de N significa "alineado por N", es decir, los datos se almacenan en la "dirección inicial %N=0". Las variables de datos en una estructura de datos se organizan en el orden en que se definen. La dirección inicial de la primera variable de datos es la dirección inicial de la estructura. Las variables de los miembros de la estructura deben estar alineadas y dispuestas, y la estructura en sí debe redondearse de acuerdo con su propio valor de alineación efectiva (es decir, la longitud total de las variables de los miembros de la estructura debe ser un múltiplo entero del valor de alineación efectiva de la estructura, como entendido en conjunto con el siguiente ejemplo). Esto hace que sea imposible comprender los valores del ejemplo anterior.

Análisis de ejemplo:

Análisis del ejemplo B;

Estructura B

{

char b; /p>

int a;

short c;

};

Supongamos que B está descargado del espacio de direcciones 0x0000. La primera variable miembro b tiene su propio valor de alineación de 1, que es menor que el valor de alineación especificado o predeterminado de 4, por lo que su valor de alineación efectivo es 1 y se almacena en la dirección 0x0000 que se ajusta a 0x0000%1=0. La segunda variable miembro a tiene su propio valor de alineación de 4, por lo que el valor de alineación efectivo también es 4, por lo que solo se puede almacenar en la dirección inicial 0x0004 a 0x0007. Revise 0x0004%4=0, junto a la primera variable. un espacio de bytes continuo. El valor de autoalineación de la tercera variable c es 2, por lo que el valor de alineación efectiva también es 2 y se puede almacenar en el espacio de bytes de 0x0008 a 0x0009, lo que es consistente con 0x0008%2=0. Entonces, de 0x0000 a 0x0009, se almacena el contenido de B. Si observamos el valor de alineación de la estructura de datos B en sí, es el valor de alineación más grande entre sus variables (aquí está b), por lo que es 4, por lo que el valor de alineación efectivo de la estructura también es 4. Por lo tanto, el espacio de dos bytes de B de 0x0008 a 0x0009 satisface 0x0008%2=0. Por lo tanto, B tiene 12 bytes de 0x0000 a 0x000B****, sizeof(struct B)=12 de hecho, si este tiene que satisfacer la alineación de bytes, debido a que su dirección inicial es 0, debe estar alineado, razón por la cual Se agregan 2 bytes al final porque el compilador quiere lograr eficiencia de acceso a la estructura de la matriz. Imagínese si definimos la estructura de la matriz B, entonces la dirección inicial de la primera estructura es 0. No hay problema, pero la primera ¿Qué pasa? las dos estructuras? Según la definición de matriz, todos los elementos de la matriz son adyacentes. Si no agregamos un tamaño de estructura que sea un múltiplo entero de 4, entonces la dirección inicial de la siguiente estructura será 0x0000A, lo que obviamente no puede satisfacer la estructura. dirección de alineación, por lo que tenemos que agregar la estructura a una estructura que sea un múltiplo entero del tamaño efectivamente alineado. De hecho, por ejemplo: para datos de tipo char, su propio valor de alineación es 1, para tipos cortos es 2, para tipos int, float, double, su propio valor de alineación es 4, el valor de alineación de estos tipos existentes también se basa en Consideraciones de matriz: solo porque se conocen las longitudes de estos tipos, también se conocen sus propios valores de alineación.

De manera similar, analice el ejemplo anterior C:

#pragma pack (2)

struct C

{

char b;

int a;

short c;

};

#pragma pack ()

El primero de estos paquetes es el primero de una serie.

La primera variable b tiene un valor de autoalineación de 1 y un valor de alineación especificado de 2, por lo que su valor de alineación efectiva es 1. Supongamos que C comienza desde 0x0000, luego b se almacena en 0x0000, lo que es consistente con 0x0000%1=0, el valor de autoalineación de la segunda variable es 4 y el valor de alineación especificado es 2, por lo que su valor de alineación efectiva es 2. por lo que se almacena en 0x0002, 0x0003, 0x0004, 0x0005 en cuatro bytes consecutivos, lo que es consistente con 0x0002%2=0. El valor de autoalineación de la tercera variable c es 2, por lo que el valor de alineación efectiva es 2 y se almacena en 0x0006, 0x0007 en secuencia, de manera consistente con 0x0006%2=0. Por lo tanto, los 8 octetos de 0x0000 a 0x00007*** almacenan las variables de C, y C mismo tiene un valor de alineación de 4, por lo que el valor de alineación efectivo de C es 2, 8%2=0, y C solo ocupa 8 bytes. de 0x0000 a 0x0007. Entonces sizeof(struct C)=8.

IV. ¿Cómo cambiar el valor de alineación predeterminado del compilador?

1. En VC IDE, puede cambiarlo de esta manera: [Proyecto]|[Configuración], pestaña c/c++ Categoría, opción Generación de código, Alineación de miembros de estructura, el valor predeterminado es 8 bytes. 2. Al codificar, se puede cambiar dinámicamente de la siguiente manera: # pragma pack Nota: Es pragma, no progma. ¿Cómo consideramos la alineación de bytes en la programación?

Si queremos ahorrar espacio al programar, solo debemos asumir que la primera dirección de la estructura es 0 y luego organizar las variables de acuerdo con los principios anteriores. El principio básico es organizar las variables. Las variables en la estructura según los tamaños de tipo se declaran en orden ascendente, minimizando la cantidad de relleno entre ellas. Otro es la eficiencia de intercambiar espacio por tiempo. Demos un ejemplo de la alineación del espacio de llenado: un método de intercambiar espacio por tiempo es insertar explícitamente miembros reservados:

estructura A{

.

char a;

char reservado[3];

char reservado[3];// uso del espacio para el tiempo