microprocessor little endian conversion big and endianness

little - Tipos de endianness



little endian bits (8)

También hay endian medio o mixto. Ver wikipedia para más detalles.

La única vez que tuve que preocuparme por esto fue cuando escribí un código de red en C. El uso de redes usualmente usa Big-endian IIRC. La mayoría de los lenguajes lo resumen o ofrecen bibliotecas para garantizar que estás usando el endian-derecho correcto.

¿Cuál es la diferencia entre los siguientes tipos de endianness?

  • byte (8b) invariante grande y pequeño endianness
  • media palabra (16b) invariante grande y poco endianness
  • palabra (32b) invariante grande y poco endianness
  • doble palabra (64b) invariante grande y poco endianness

¿Hay otros tipos / variaciones?


el concepto básico es el orden de los bits:

1010 0011

en little-endian es lo mismo que

0011 1010

en big-endian (y viceversa).

Notará que el orden cambia por agrupación, no por bit individual. No sé de un sistema, por ejemplo, donde

1100 0101

sería la versión "other-endian" de la primera versión.



En realidad, describiría el endianismo de una máquina como el orden de los bytes dentro de una palabra, y no el orden de los bits .

Por "bytes" allá me refiero a la "unidad de memoria más pequeña que la arquitectura puede gestionar individualmente". Por lo tanto, si la unidad más pequeña tiene 16 bits de longitud (lo que en x86 se llamaría una palabra ), una "palabra" de 32 bits que representa el valor 0xFFFF0000 podría almacenarse así:

FFFF 0000

o esto:

0000 FFFF

en memoria, dependiendo de endianness.

Por lo tanto, si tiene endianidad de 8 bits, significa que cada palabra que consta de 16 bits se almacenará como:

FF 00

o:

00 FF

y así.


Hay dos enfoques para el mapeo endian: invariancia de direcciones e invariancia de datos .

Dirección Invariancia

En este tipo de mapeo, la dirección de los bytes se conserva siempre entre grande y pequeño. Esto tiene el efecto secundario de invertir el orden de importancia (más significativo a menos significativo) de un dato particular (por ejemplo, palabra de 2 o 4 bytes) y, por lo tanto, la interpretación de los datos. Específicamente, en little-endian, la interpretación de datos es menos significativa para los bytes más significativos, mientras que en big-endian, la interpretación es de lo más significativo a lo menos significativo. En ambos casos, el conjunto de bytes a los que se accede sigue siendo el mismo.

Ejemplo

Invarianza de dirección (también conocida como invarianza de bytes ): la dirección de byte es constante pero la importancia de bytes se invierte.

Addr Memory 7 0 | | (LE) (BE) |----| +0 | aa | lsb msb |----| +1 | bb | : : |----| +2 | cc | : : |----| +3 | dd | msb lsb |----| | | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0xaa (preserved) Read 2 bytes: 0xbbaa 0xaabb Read 4 bytes: 0xddccbbaa 0xaabbccdd

Invarianza de datos

En este tipo de mapeo, la importancia del byte relativo se conserva para el dato de un tamaño particular. Por lo tanto, existen diferentes tipos de asignaciones endian invariantes de datos para diferentes tamaños de dato. Por ejemplo, un mapeo de endian invariante de palabra de 32 bits se usaría para un tamaño de dato de 32. El efecto de preservar el valor de dato de tamaño particular es que las direcciones de byte de bytes dentro del dato se invierten entre mapeos de endian grande y pequeño .

Ejemplo

Invarianza de datos de 32 bits (también conocida como invarianza de palabras ): el datum es una palabra de 32 bits que siempre tiene el valor 0xddccbbaa , independientemente de la endianidad. Sin embargo, para accesos menores a una palabra, la dirección de los bytes se invierte entre grandes y pequeñas asignaciones endian.

Addr Memory | +3 +2 +1 +0 | <- LE |-------------------| +0 msb | dd | cc | bb | aa | lsb |-------------------| +4 msb | 99 | 88 | 77 | 66 | lsb |-------------------| BE -> | +0 +1 +2 +3 | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0xdd Read 2 bytes: 0xbbaa 0xddcc Read 4 bytes: 0xddccbbaa 0xddccbbaa (preserved) Read 8 bytes: 0x99887766ddccbbaa 0x99887766ddccbbaa (preserved)

Ejemplo

Invarianza de datos de 16 bits (también conocida como invarianza de media palabra ): el dato es un 16 bits que siempre tiene el valor 0xbbaa , independientemente de la endianidad. Sin embargo, para accesos de menos de media palabra, la dirección de los bytes se invierte entre grandes y pequeñas asignaciones endian.

Addr Memory | +1 +0 | <- LE |---------| +0 msb | bb | aa | lsb |---------| +2 msb | dd | cc | lsb |---------| +4 msb | 77 | 66 | lsb |---------| +6 msb | 99 | 88 | lsb |---------| BE -> | +0 +1 | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0xbb Read 2 bytes: 0xbbaa 0xbbaa (preserved) Read 4 bytes: 0xddccbbaa 0xddccbbaa (preserved) Read 8 bytes: 0x99887766ddccbbaa 0x99887766ddccbbaa (preserved)

Ejemplo

Invarianza de datos de 64 bits (también conocida como invarianza de palabras dobles ): el datum es una palabra de 64 bits que siempre tiene el valor 0x99887766ddccbbaa , independientemente de la endianidad. Sin embargo, para accesos más pequeños que una palabra doble, la dirección de los bytes se invierte entre grandes y pequeñas asignaciones endian.

Addr Memory | +7 +6 +5 +4 +3 +2 +1 +0 | <- LE |---------------------------------------| +0 msb | 99 | 88 | 77 | 66 | dd | cc | bb | aa | lsb |---------------------------------------| BE -> | +0 +1 +2 +3 +4 +5 +6 +7 | At Addr=0: Little-endian Big-endian Read 1 byte: 0xaa 0x99 Read 2 bytes: 0xbbaa 0x9988 Read 4 bytes: 0xddccbbaa 0x99887766 Read 8 bytes: 0x99887766ddccbbaa 0x99887766ddccbbaa (preserved)


En términos prácticos, endianess se refiere a la forma en que el procesador interpretará el contenido de una ubicación de memoria determinada. Por ejemplo, si tenemos la ubicación de memoria 0x100 con el siguiente contenido (bytes hexadecimales)

0x100: 12 34 56 78 90 ab cd ef Reads Little Endian Big Endian 8-bit: 12 12 16-bit: 34 12 12 34 32-bit: 78 56 34 12 12 34 56 78 64-bit: ef cd ab 90 78 56 34 12 12 34 56 78 90 ab cd ef

Las dos situaciones en las que debes tener en cuenta la endialeza son con el código de red y si lo haces con los punteros.

TCP / IP especifica que los datos en el cable deben ser big endian. Si transmite tipos que no sean matrices de bytes (como punteros a estructuras), debe asegurarse de usar las macros ntoh / hton para garantizar que los datos se envíen a big endian. Si envía desde un procesador little-endian a un procesador big-endian (o viceversa), los datos se distorsionarán ...

Casting issues:

uint32_t* lptr = 0x100; uint16_t data; *lptr = 0x0000FFFF data = *((uint16_t*)lptr);

¿Cuál será el valor de los datos? En un sistema big-endian, sería 0 en un sistema little-endian, sería FFFF


Hace 13 años trabajé en una herramienta portátil tanto para un sistema DEC ALPHA como para una PC. En este DEC ALFA, los bits en realidad estaban invertidos . Es decir:

1010 0011

en realidad traducido a

1100 0101

Era casi transparente y sin fisuras en el código C, excepto que tenía un bitfield declarado como

typedef struct { int firstbit:1; int middlebits:10; int lastbits:21; };

que necesitaba ser traducido a (usando la compilación condicional #ifdef)

typedef struct { int lastbits:21; int middlebits:10; int firstbit:1; };


Philibert dijo:

bits fueron invertidos

Dudo que cualquier arquitectura rompa la invarianza de valores de bytes. El orden de los campos de bits puede necesitar inversión al mapear estructuras que los contienen contra datos. Tal mapeo directo se basa en los detalles del compilador que están fuera del estándar C99 pero que aún pueden ser comunes. El mapeo directo es más rápido pero no cumple con el estándar C99 que no estipula el empaque, la alineación y el orden de bytes. El código que cumple con C99 debe usar un mapeo lento basado en valores en lugar de direcciones. Es decir, en lugar de hacer esto,

#if LITTLE_ENDIAN struct breakdown_t { int least_significant_bit: 1; int middle_bits: 10; int most_significant_bits: 21; }; #elif BIG_ENDIAN struct breakdown_t { int most_significant_bits: 21; int middle_bits: 10; int least_significant_bit: 1; }; #else #error Huh #endif uint32_t data = ...; struct breakdown_t *b = (struct breakdown_t *)&data;

uno debería escribir esto (y así es como el compilador generaría código de todos modos, incluso para el "mapeo directo" anterior),

uint32_t data = ...; uint32_t least_significant_bit = data & 0x00000001; uint32_t middle_bits = (data >> 1) & 0x000003FF; uint32_t most_significant_bits = (data >> 11) & 0x001fffff;

La razón detrás de la necesidad de invertir el orden de los campos de bits en cada unidad de almacenamiento de datos específica de aplicación endian-neutral es que los compiladores empaquetan campos de bits en bytes de direcciones crecientes.

El "orden de los bits" en cada byte no importa ya que la única forma de extraerlos es aplicando máscaras de valores y cambiando a la dirección del bit menos significativo o del bit más significativo. La cuestión del "orden de bits" solo sería importante en las arquitecturas imaginarias con la noción de direcciones de bit. Creo que todas las arquitecturas existentes ocultan esta noción en hardware y proporcionan solo la extracción de bit menos significativa frente a la más significativa, que es la noción basada en los valores de byte neutro endian.