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?
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?
Respuestas:
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'.
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 ...
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 ...
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.
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.
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)
0x12345678
se almacena como 78 56 34 12
mientras 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)-1
permutas. 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).
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 memcmp
para 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 ...
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.
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.
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:
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).
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 :)
for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }
corresponde a move.l data, num
una CPU big endian.
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.
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).
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.