¿Cuál es la ventaja del formato little endian?

140

Los procesadores Intel (y quizás algunos otros) usan el formato little endian para almacenamiento.

Siempre me pregunto por qué alguien querría almacenar los bytes en orden inverso. ¿Tiene este formato alguna ventaja sobre el formato big endian?

Galleta
fuente
1
El 6502 fue un procesador en fase inicial (¿el primero?). Parece recordar alguna afirmación de que es poco endian para algunos problemas relacionados con el rendimiento debido a la tubería, pero ahora no tengo idea de cuál podría haber sido ese problema. ¿Alguna sugerencia?
Steve314
1
@ Steve314: Mi respuesta explica cómo Little Endian ayuda con el rendimiento en una CPU canalizada: programmers.stackexchange.com/q/95854/27874
Martin Vilcans
3
Little-endian, big-endian: debes elegir uno u otro. Como conducir por el lado izquierdo o derecho del camino.
3
Le sugiero que escriba algún código en ASM, preferiblemente para una arquitectura de la "vieja escuela" como 6502 o Z80. Inmediatamente verás por qué estos usan little endian. Las arquitecturas que usan big endian tienen ciertas características de su conjunto de instrucciones que hacen que ese formato sea preferible. ¡No es una decisión arbitraria!
Stefan Paul Noack
2
Cada sistema de orden de bytes tiene sus ventajas. Las máquinas little-endian le permiten leer primero el byte más bajo, sin leer los otros. Puedes verificar si un número es par o impar (el último bit es 0) muy fácilmente, lo cual es genial si te gusta ese tipo de cosas. Los sistemas big-endian almacenan datos en la memoria de la misma manera que los humanos pensamos en los datos (de izquierda a derecha), lo que facilita la depuración de bajo nivel.
Koray Tugay

Respuestas:

198

Hay argumentos de cualquier manera, pero un punto es que en un sistema little endian, la dirección de un valor dado en la memoria, tomada como un ancho de 32, 16 u 8 bits, es la misma.

En otras palabras, si tiene en memoria un valor de dos bytes:

0x00f0   16
0x00f1    0

tomar ese '16' como un valor de 16 bits (c 'corto' en la mayoría de los sistemas de 32 bits) o como un valor de 8 bits (generalmente c 'char') cambia solo la instrucción de búsqueda que usa, no la dirección que busca de.

En un sistema big-endian, con lo anterior presentado como:

0x00f0    0
0x00f1   16

necesitaría incrementar el puntero y luego realizar la operación de búsqueda más estrecha en el nuevo valor.

Entonces, en resumen, 'en pequeños sistemas endianos, los elencos son un no-op'.

jimwise
fuente
3
Suponiendo, por supuesto, que los bytes de alto orden que no leyó pueden ignorarse razonablemente (por ejemplo, sabe que son cero de todos modos).
Steve314
10
@ Steve314: Si estoy en C downcasting de 32 a 16 bits (por ejemplo) en un sistema de complemento a 2, la gran mayoría de los sistemas, los bytes no necesitan ser cero para ser ignorados. Independientemente de su valor, puedo ignorarlos y seguir cumpliendo con el estándar C y las expectativas del programador.
99
@Stritzinger: estamos hablando del código de ensamblaje / máquina generado por un compilador, que no puede ser portátil. El código de idioma de nivel superior para compilar es portátil: solo se compila para diferentes operaciones en las diferentes arquitecturas (como lo hacen todas las operaciones).
jimwise
77
No creo este argumento, porque en las arquitecturas big-endian, un puntero podría apuntar al final, en lugar del principio, de lo que sea que se refiera y de lo que tendría exactamente la misma ventaja.
dan_waterworth
44
@dan_waterworth no del todo: tenga en cuenta las reglas aritméticas del puntero en C, por ejemplo, y lo que sucede cuando aumenta o disminuye los lanzamientos del mismo puntero. Puedes mover la complejidad, pero no puedes eliminarla.
jimwise
45

Siempre me pregunto por qué alguien querría almacenar los bytes en orden inverso.

Big-endian y little-endian son solo "orden normal" y "orden inverso" desde una perspectiva humana, y solo si todo esto es cierto ...

  1. Estás leyendo los valores en la pantalla o en papel.
  2. Pones las direcciones de memoria más bajas a la izquierda y las más altas a la derecha.
  3. Estás escribiendo en hexadecimal, con el nybble de alto orden a la izquierda, o binario, con el bit más significativo a la izquierda.
  4. Lees de izquierda a derecha.

Esas son todas las convenciones humanas que no importan en absoluto para una CPU. Si tuviera que retener el n. ° 1 y n. ° 2, y cambiar el n. ° 3, little-endian parecería "perfectamente natural" para las personas que leen árabe o hebreo, que están escritas de derecha a izquierda.

Y hay otras convenciones humanas que hacen que el big endian parezca antinatural, como ...

  • El byte "más alto" (más significativo) debe estar en la dirección de memoria "más alta".

Cuando estaba programando principalmente 68K y PowerPC, consideraba que big-endian era "correcto" y little-endian era "incorrecto". Pero como he estado haciendo más trabajo ARM e Intel, me he acostumbrado a little-endian. Realmente no importa.

Bob Murphy
fuente
30
De hecho, los números se escriben del [dígito más significativo] de la izquierda al [dígito menos significativo] de la derecha en árabe y hebreo.
Random832
55
Entonces, ¿por qué los bits dentro de un byte se almacenan en formato "big endian"? ¿Por qué no ser consistente?
tskuzzy
11
No lo son: el bit 0 es, por convención, el menos significativo y el bit 7 el más significativo. Además, generalmente no puede ordenar los bits dentro de un byte, ya que los bits no son direccionables individualmente. Por supuesto, pueden tener un orden físico en un protocolo de comunicación o medio de almacenamiento determinado, pero a menos que esté trabajando en el nivel de protocolo o hardware de bajo nivel, no necesita preocuparse por este orden.
Stewart
3
BlueRaja: solo por convención de escritura en papel. Esto no tiene nada en común con la arquitectura de la CPU. Puede escribir el byte como 0-7 LSB-MSB en lugar de 7-0 MSB-LSB y nada cambia desde el punto de vista del algoritmo.
SF.
2
@SF .: "Presione brevemente, haga estallar cualquier cosa menos corta " de todos modos le sorprenderá. Incluso si no está corrompiendo la pila presionando bytes que nunca aparece o viceversa ... x86 (32 bits), por ejemplo, realmente quiere que la pila esté alineada con palabras, y empuje o haga estallar cualquier cosa que cause el apilar el puntero para que no sea múltiplo de 4 puede causar problemas de alineación. E incluso si no fuera así, las cosas empujan una palabra completa / dword / qword / etc a la vez, por lo que el byte bajo seguirá siendo el primero que obtenga cuando aparezca.
cHao
41

Bien, esta es la razón que me han explicado: suma y resta

Cuando sumas o restas números de varios bytes, debes comenzar con el byte menos significativo. Si está agregando dos números de 16 bits, por ejemplo, puede haber una transferencia desde el byte menos significativo al byte más significativo, por lo que debe comenzar con el byte menos significativo para ver si hay una transferencia. Esta es la misma razón por la que comienzas con el dígito más a la derecha cuando haces la suma a mano. No puedes comenzar desde la izquierda.

Considere un sistema de 8 bits que recupera bytes secuencialmente de la memoria. Si primero obtiene el byte menos significativo , puede comenzar a hacer la adición mientras el byte más significativo se obtiene de la memoria. Este paralelismo es la razón por la cual el rendimiento es mejor en little endian, como en el sistema. Si tuviera que esperar hasta que ambos bytes fueran recuperados de la memoria, o recuperarlos en el orden inverso, tomaría más tiempo.

Esto está en los viejos sistemas de 8 bits. En una CPU moderna, dudo que el orden de bytes haga alguna diferencia y usamos little endian solo por razones históricas.

Martin Vilcans
fuente
3
Ah, así que es más o menos la misma razón por la que uso el orden de trozos little-endian para enteros grandes. Debería haberlo resuelto. La gente realmente necesita trabajar en cibernética ahora : mi cerebro ya necesita desesperadamente algunas piezas de repuesto y algunas actualizaciones radicales, ¡no puedo esperar para siempre!
Steve314
2
Una idea: el 6502 no hacía muchos cálculos matemáticos de 16 bits en hardware, era, después de todo, un procesador de 8 bits. Pero sí hizo un direccionamiento relativo, utilizando compensaciones firmadas de 8 bits en relación con una dirección base de 16 bits.
Steve314
2
Tenga en cuenta que esta idea todavía es importante para la aritmética de enteros de precisión múltiple (como dijo Steve314), pero a nivel de palabra. Ahora, la mayoría de las operaciones no se ven directamente afectadas por la endianness del procesador: todavía se puede almacenar la palabra menos significativa primero en un sistema big-endian, como lo hace GMP. Los procesadores little-endian todavía tienen una ventaja para las pocas operaciones (por ejemplo, ¿algunas conversiones de cadenas?) Que podrían hacerse más fácilmente leyendo un byte a la vez, ya que solo en un sistema little-endian, el orden de los bytes es correcto.
vinc17
los procesadores little endian tienen una ventaja en caso de que el ancho de banda de la memoria sea limitado, como en algunos procesadores ARM de 32 bits con bus de memoria de 16 bits, o el 8088 con bus de datos de 8 bits: el procesador puede cargar la mitad baja y hacer add / sub / mul ... con él mientras espera la mitad superior
phuclv
13

Con los procesadores de 8 bits fue ciertamente más eficiente, podría realizar una operación de 8 o 16 bits sin necesidad de un código diferente y sin necesidad de almacenar valores adicionales.

Todavía es mejor para algunas operaciones de suma si se trata de un byte a la vez.

Pero no hay razón para que big-endian sea más natural: en inglés se usa trece (little endian) y veintitrés (big endian)

Martin Beckett
fuente
1
Big-endian es de hecho más fácil para los humanos porque no requiere reorganizar los bytes. Por ejemplo, en una PC, 0x12345678se almacena como 78 56 34 12mientras que en un sistema BE lo es 12 34 56 78(el byte 0 está a la izquierda, el byte 3 está a la derecha). Observe cómo cuanto mayor es el número (en términos de bits), más intercambio requiere; una PALABRA requeriría un intercambio; un DWORD, dos pases (tres intercambios totales); un QWORD tres pases (7 en total), y así sucesivamente. Es decir, (bits/8)-1permutas. Otra opción que está leyendo tanto hacia delante y hacia atrás (leer cada byte hacia delante, pero el escaneo de todo el # al revés).
Synetech
Ciento trece es endian medio o big endian con "trece" que es esencialmente un dígito no decimal. Cuando explicamos en detalle los números, hay algunas desviaciones menores de las convenciones constante de base que utilizamos para los dígitos, pero una vez que se tira a cabo esos casos especiales, el resto es bigEndian - ante miles de millones, miles de personas antes cientos etc.
Steve314
@ Synetech: afortunadamente, a la computadora no le importa cómo los lean los humanos. Eso es como afirmar que el flash NAND es mejor porque ot '
Martin Beckett
1
@ Steve314, las palabras deletreadas de números no importan, es la lectura numérica que es lo que usamos cuando programamos. Martin, las computadoras no tienen que preocuparse por cómo los humanos leen los números, pero si es fácil para los humanos leerlos, entonces la programación (u otro trabajo relacionado) se vuelve más fácil y se pueden reducir o evitar algunos defectos y fallas.
Synetech
@ steve314 Y en danés, "95" se pronuncia "fem halvfems" (cinco, más cuatro años y medio).
Vatine
7

La convención japonesa de fechas es "big endian": aaaa / mm / dd. Esto es útil para los algoritmos de clasificación, que pueden usar una simple comparación de cadenas con la regla usual de primer carácter es la más significativa.

Algo similar se aplica a los números big-endian almacenados en un registro de primer campo más significativo. El orden de importancia de los bytes dentro de los campos coincide con la importancia de los campos dentro del registro, por lo que puede usar a memcmppara comparar registros, sin importarle mucho si está comparando dos palabras largas, cuatro palabras u ocho bytes separados.

Cambie el orden de importancia de los campos y obtendrá la misma ventaja, pero para números little-endian en lugar de big-endian.

Esto tiene muy poca importancia práctica, por supuesto. Si su plataforma es big-endian o little-endian, puede solicitar campos de registros para explotar este truco si realmente lo necesita. Es simplemente un dolor si necesitas escribir código portátil .

También podría incluir un enlace al recurso clásico ...

http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt

EDITAR

Un pensamiento extra. Una vez escribí una gran biblioteca de enteros (para ver si podía), y para eso, los fragmentos de 32 bits de ancho se almacenan en orden little-endian, independientemente de cómo la plataforma ordena los bits en esos fragmentos. Las razones fueron ...

  1. Muchos algoritmos, naturalmente, comienzan a funcionar en el extremo menos significativo y quieren que esos extremos coincidan. Por ejemplo, además, el transporte se propaga a dígitos cada vez más significativos, por lo que tiene sentido comenzar en el extremo menos significativo.

  2. Aumentar o reducir un valor solo significa agregar / eliminar fragmentos al final, no es necesario mover los fragmentos hacia arriba / abajo. La copia puede ser necesaria debido a la reasignación de memoria, pero no con frecuencia.

Esto no tiene una relevancia obvia para los procesadores, por supuesto, hasta que las CPU se realicen con soporte de enteros grandes de hardware, es puramente una biblioteca.

Steve314
fuente
7

Nadie más ha respondido POR QUÉ esto podría hacerse, muchas cosas sobre las consecuencias.

Considere un procesador de 8 bits que puede cargar un solo byte desde la memoria en un ciclo de reloj dado.

Ahora, si desea cargar un valor de 16 bits, en (digamos) el único registro de 16 bits que tiene, es decir, el contador del programa, entonces una forma simple de hacerlo es:

  • Cargue un byte desde la ubicación de recuperación
  • desplazar ese byte a la izquierda 8 lugares
  • Incrementar la ubicación de recuperación de memoria en 1
  • cargar el siguiente byte (en la parte de orden inferior del registro)

el resultado: solo incrementa la ubicación de búsqueda, solo carga en la parte de orden inferior de su registro más amplio y solo necesita poder desplazarse a la izquierda. (Por supuesto, desplazarse a la derecha es útil para otras operaciones, por lo que esta es una especie de espectáculo secundario).

Una consecuencia de esto es que las cosas de 16 bits (doble byte) se almacenan en el orden Más ... Menos. Es decir, la dirección más pequeña tiene el byte más significativo, un endian tan grande.

Si en su lugar trataste de cargar usando little endian, necesitarías cargar un byte en la parte inferior de tu registro ancho, luego cargar el siguiente byte en un área de ensayo, desplazarlo y luego meterlo en la parte superior de tu registro más ancho . O use una disposición de compuerta más compleja para poder cargar selectivamente en el byte superior o inferior.

El resultado de tratar de hacer little endian es que necesita más silicio (interruptores y puertas) o más operaciones.

En otras palabras, en términos de obtener ganancias por dinero en los viejos tiempos, obtuviste más por la mayoría del rendimiento y el área de silicio más pequeña.

En estos días, estas consideraciones son bastante irrelevantes, pero cosas como el llenado de tuberías pueden ser un poco importantes.

Cuando se trata de escribir s / w, la vida es con frecuencia más fácil cuando se usa un pequeño direccionamiento endian.

(Y los procesadores big endian tienden a ser big endian en términos de orden de bytes y little endian en términos de bits en bytes. Pero algunos procesadores son extraños y utilizarán el orden de bits big endian y el orden de bytes. Esto hace la vida muy interesante para el diseñador h / w que agrega periféricos mapeados en memoria, pero no tiene otra consecuencia para el programador).

rápidamente_ahora
fuente
3

jimwise hizo un buen punto. Hay otro problema, en little endian puedes hacer lo siguiente:

byte data[4];
int num=0;
for(i=0;i<4;i++)
    num += data[i]<<i*8; 

OR 

num = *(int*)&data; //is interpreted as

mov dword data, num ;or something similar it has been some time

Más directo para los programadores que no se ven afectados por la desventaja obvia de las ubicaciones intercambiadas en la memoria. Personalmente, creo que Big Endian es inverso de lo que es natural :). 12 debe almacenarse y escribirse como 21 :)

Cem Kalyoncu
fuente
1
Esto solo prueba que es más rápido / fácil trabajar en cualquier formato que sea nativo de la CPU. No dice nada sobre si es mejor. Lo mismo ocurre con big endian: for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }corresponde a move.l data, numuna CPU big endian.
Martin Vilcans
@martin: una resta menos es mejor en mi libro
Cem Kalyoncu
Realmente no importa, ya que el compilador desenrollará el bucle de todos modos. En cualquier caso, muchas CPU tienen instrucciones de intercambio de bytes para manejar este problema.
Martin Vilcans
no estoy de acuerdo bcoz en big endian, haría {num << = 8; num | = datos [i]; } al menos esto no tiene que calcular el conteo de desplazamiento a la izquierda usando mul
Hayri Uğur Koltuk
@ali: su código hará la operación exacta que escribí y no funcionará en big endian.
Cem Kalyoncu
1

Siempre me pregunto por qué alguien querría almacenar los bytes en orden inverso

Los números decimales se escriben big endian. También cómo lo escribes en inglés. Empiezas con el dígito más significativo y el siguiente más significativo al menos significativo. p.ej

1234

es mil doscientos treinta y cuatro.

Esta es la forma en que Big Endian a veces se llama el orden natural.

En little endian, este número sería uno, veinte, trescientos cuatro mil.

Sin embargo, cuando realiza operaciones aritméticas como sumas o restas, comienza con el final.

  1234
+ 0567
  ====

Comienza con 4 y 7, escribe el dígito más bajo y recuerda el carry. Luego sumas 3 y 6, etc. Para sumar, restar o comparar, es más sencillo de implementar, si ya tienes lógica para leer la memoria en orden, si los números están invertidos.

Para admitir Big Endian de esta manera, necesita lógica para leer la memoria en reversa, o tiene un proceso RISC que solo opera en registros. ;)

Gran parte del diseño Intel x86 / Amd x64 es histórico.

Peter Lawrey
fuente
0

Big-endian es útil para algunas operaciones (comparaciones de "bignums" de muelles de igual longitud de octeto). Little-endian para otros (agregando dos "bignums", posiblemente). Al final, depende de para qué se haya configurado el hardware de la CPU, generalmente es uno u otro (algunos chips MIPS eran, IIRC, conmutables en el arranque para ser LE o BE).

Vatine
fuente
0

Cuando solo se trata de almacenamiento y transferencia con longitudes variables, pero no de aritmética con valores múltiples, entonces LE es generalmente más fácil de escribir, mientras que BE es más fácil de leer.

Tomemos una conversión de int a string (y viceversa) como un ejemplo específico.

int val_int = 841;
char val_str[] = "841";

Cuando int se convierte en la cadena, el dígito menos significativo es más fácil de extraer que el dígito más significativo. Todo se puede hacer en un bucle simple con una condición final simple.

val_int = 841;
// Make sure that val_str is large enough.

i = 0;
do // Write at least one digit to care for val_int == 0
{
    // Constants, can be optimized by compiler.
    val_str[i] = '0' + val_int % 10;
    val_int /= 10;
    i++;
}
while (val_int != 0);

val_str[i] = '\0';
// val_str is now in LE "148"
// i is the length of the result without termination, can be used to reverse it

Ahora intente lo mismo en el orden BE. Por lo general, necesita otro divisor que tenga la mayor potencia de 10 para el número específico (aquí 100). Primero necesitas encontrar esto, por supuesto. Mucho más cosas que hacer.

La conversión de cadena a int es más fácil de hacer en BE, cuando se realiza como la operación de escritura inversa. Escribir almacena el último dígito más significativo, por lo que debe leerse primero.

val_int = 0;
length = strlen(val_str);

for (i = 0; i < length; i++)
{
    // Again a simple constant that can be optimized.
    val_int = 10*val_int + (val_str[i] - '0');
}

Ahora haga lo mismo en orden LE. Nuevamente, necesitaría un factor adicional que comience con 1 y se multiplique por 10 para cada dígito.

Por lo tanto, generalmente prefiero usar BE para el almacenamiento, porque un valor se escribe exactamente una vez, pero se lee al menos una vez y tal vez muchas veces. Por su estructura más simple, generalmente también tomo la ruta para convertir a LE y luego invertir el resultado, incluso si escribe el valor por segunda vez.

Otro ejemplo para el almacenamiento BE sería la codificación UTF-8 y muchos más.

Seguro
fuente