I processori Intel (e forse alcuni altri) utilizzano il formato little endian per l'archiviazione.
Mi chiedo sempre perché qualcuno voglia archiviare i byte in ordine inverso. Questo formato presenta dei vantaggi rispetto al formato big endian?
I processori Intel (e forse alcuni altri) utilizzano il formato little endian per l'archiviazione.
Mi chiedo sempre perché qualcuno voglia archiviare i byte in ordine inverso. Questo formato presenta dei vantaggi rispetto al formato big endian?
Risposte:
Ci sono argomenti in entrambi i modi, ma un punto è che in un sistema little-endian, l'indirizzo di un dato valore in memoria, preso come una larghezza di 32, 16 o 8 bit, è lo stesso.
In altre parole, se hai in memoria un valore di due byte:
0x00f0 16
0x00f1 0
prendendo quel '16' come valore a 16 bit (c 'corto' sulla maggior parte dei sistemi a 32 bit) o come valore a 8 bit (generalmente c 'char') cambia solo l'istruzione di recupero che usi - non l'indirizzo che recuperi a partire dal.
Su un sistema big-endian, con quanto sopra esposto come:
0x00f0 0
0x00f1 16
è necessario incrementare il puntatore e quindi eseguire l'operazione di recupero più stretta sul nuovo valore.
Quindi, in breve, "sui sistemi little endian, i cast non sono operativi".
Mi chiedo sempre perché qualcuno voglia archiviare i byte in ordine inverso.
Big-endian e little-endian sono solo "ordine normale" e "ordine inverso" da una prospettiva umana, e quindi solo se tutti questi sono veri ...
Quelle sono tutte convenzioni umane che non contano affatto per una CPU. Se dovessi conservare # 1 e # 2 e capovolgere # 3, il little-endian sembrerebbe "perfettamente naturale" alle persone che leggono l'arabo o l'ebraico, che sono scritte da destra a sinistra.
E ci sono altre convenzioni umane che rendono il big-endian che sembra innaturale, come ...
Quando programmavo principalmente 68K e PowerPC, consideravo il "big endian" "giusto" e il little-endian "sbagliato". Ma dal momento che ho lavorato di più su ARM e Intel, mi sono abituato a little-endian. Non importa davvero.
OK, ecco il motivo che mi è stato spiegato: addizione e sottrazione
Quando aggiungi o sottrai numeri multi-byte, devi iniziare con il byte meno significativo. Se ad esempio aggiungi due numeri a 16 bit, potrebbe esserci un carry dal byte meno significativo al byte più significativo, quindi devi iniziare con il byte meno significativo per vedere se c'è un carry. Questo è lo stesso motivo per cui inizi con la cifra più a destra quando esegui l'aggiunta manuale. Non puoi iniziare da sinistra.
Si consideri un sistema a 8 bit che recupera i byte in sequenza dalla memoria. Se recupera prima il byte meno significativo , può iniziare a fare l'aggiunta mentre il byte più significativo viene recuperato dalla memoria. Questo parallelismo è il motivo per cui le prestazioni sono migliori in little endian su un sistema. Se dovesse attendere fino a quando entrambi i byte non sono stati recuperati dalla memoria, oppure recuperarli nell'ordine inverso, occorrerebbe più tempo.
Questo è su vecchi sistemi a 8 bit. Su una CPU moderna dubito che l'ordine dei byte faccia la differenza e usiamo little endian solo per motivi storici.
Con i processori a 8 bit è stato sicuramente più efficiente, è possibile eseguire un'operazione a 8 o 16 bit senza la necessità di codice diverso e senza necessità di bufferizzare valori aggiuntivi.
È ancora meglio per alcune operazioni di aggiunta se si tratta di un byte alla volta.
Ma non c'è motivo per cui il big-endian sia più naturale - in inglese usi tredici (little endian) e ventitre (big endian)
0x12345678
è memorizzato come 78 56 34 12
mentre su un sistema BE è 12 34 56 78
(il byte 0 è a sinistra, il byte 3 è a destra). Nota quanto maggiore è il numero (in termini di bit), maggiore è lo scambio che richiede; una WORD richiederebbe uno scambio; un DWORD, due passaggi (tre scambi totali); una QWORD tre passaggi (7 in totale) e così via. Cioè, (bits/8)-1
swap. Un'altra opzione è leggerli sia in avanti che all'indietro (leggendo ogni byte in avanti, ma scansionando l'intero # indietro).
La convenzione della data giapponese è "big endian" - yyyy / mm / dd. Questo è utile per gli algoritmi di ordinamento, che possono utilizzare un semplice confronto di stringhe con la solita regola del primo carattere è la più significativa.
Qualcosa di simile si applica ai numeri big-endian archiviati in un record di primo campo molto significativo. L'ordine di significatività dei byte all'interno dei campi corrisponde al significato dei campi all'interno del record, quindi è possibile utilizzare a memcmp
per confrontare i record, senza preoccuparsi molto se si stanno confrontando due parole lunghe, quattro parole o otto byte separati.
Capovolgi l'ordine di significatività dei campi e otterrai lo stesso vantaggio, ma per i numeri little-endian piuttosto che big-endian.
Questo ha ben poco significato pratico, ovviamente. Che la tua piattaforma sia big-endian o little-endian, puoi ordinare un campo record per sfruttare questo trucco se ne hai davvero bisogno. È solo una seccatura se devi scrivere un codice portatile .
Potrei anche includere un link all'appello classico ...
http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt
MODIFICARE
Un pensiero in più. Una volta ho scritto una grande libreria di numeri interi (per vedere se potevo), e per questo i blocchi a 32 bit di larghezza sono memorizzati in un ordine little-endian, indipendentemente da come la piattaforma ordina i bit in quei blocchi. Le ragioni erano ...
Molti algoritmi iniziano naturalmente a funzionare all'estremità meno significativa e vogliono che tali fini siano abbinati. Ad esempio, inoltre, si porta a cifre sempre più significative, quindi ha senso iniziare alla fine meno significativa.
Crescere o ridurre un valore significa solo aggiungere / rimuovere blocchi alla fine - non è necessario spostare i blocchi su / giù. La copia potrebbe essere ancora necessaria a causa della riallocazione della memoria, ma non spesso.
Ciò non ha alcuna ovvia rilevanza per i processori, ovviamente - fino a quando le CPU non sono realizzate con il supporto hardware di grandi numeri interi, è puramente una questione di libreria.
Nessun altro ha risposto PERCHÉ questo potrebbe essere fatto, molte cose sulle conseguenze.
Si consideri un processore a 8 bit che può caricare un singolo byte dalla memoria in un determinato ciclo di clock.
Ora, se vuoi caricare un valore a 16 bit, nel (solo) unico registro a 16 bit che hai - cioè il contatore del programma, allora un modo semplice per farlo è:
il risultato: si incrementa sempre e solo la posizione di recupero, si carica sempre nella parte di ordine inferiore del registro più ampio e si deve solo spostare a sinistra. (Naturalmente, spostare a destra è utile per altre operazioni, quindi questo è un po 'uno spettacolo secondario.)
Una conseguenza di ciò è che il materiale a 16 bit (doppio byte) è memorizzato nell'ordine Most..Least. Cioè, l'indirizzo più piccolo ha il byte più significativo - quindi big endian.
Se invece hai provato a caricare usando little endian, dovresti caricare un byte nella parte inferiore del registro largo, quindi caricare il byte successivo in un'area di gestione temporanea, spostarlo e quindi inserirlo nella parte superiore del registro più largo . Oppure utilizza una disposizione più complessa del gate per poter caricare selettivamente nel byte superiore o inferiore.
Il risultato del tentativo di diventare little endian è che hai bisogno di più silicio (interruttori e cancelli) o di più operazioni.
In altre parole, in termini di recupero di denaro ai vecchi tempi, hai ottenuto più bang per la maggior parte delle prestazioni e la più piccola area di silicio.
In questi giorni, queste considerazioni e praticamente irrilevanti, ma cose come il riempimento della pipeline potrebbero essere ancora un po 'un grosso problema.
Quando si tratta di scrivere s / w, la vita è spesso più facile quando si usa un indirizzamento di little endian.
(E i processori big endian tendono ad essere big endian in termini di ordinamento dei byte e little endian in termini di bit in byte. Ma alcuni processori sono strani e useranno l'ordinamento di bit big endian e l'ordinamento di byte. Questo rende la vita molto interessante per il progettista h / w che aggiunge periferiche mappate in memoria ma non ha altre conseguenze per il programmatore.)
jimwise ha fatto un buon punto. C'è un altro problema, in little endian puoi fare quanto segue:
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
Più semplice per i programmatori che non sono interessati dall'ovvio svantaggio delle posizioni scambiate nella memoria. Personalmente trovo che il big endian sia l'inverso di ciò che è naturale :). 12 devono essere memorizzati e scritti come 21 :)
for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }
corrisponde a move.l data, num
una CPU big endian.
Mi chiedo sempre perché qualcuno voglia archiviare i byte in ordine inverso
I numeri decimali sono scritti in big endian. È anche come lo scrivi in inglese. Inizia con la cifra più significativa e la successiva dalla più significativa alla meno significativa. per esempio
1234
è milleduecentotrentaquattro.
In questo modo il big endian viene talvolta chiamato ordine naturale.
In little endian, questo numero sarebbe uno, venti, trecentoquattromila.
Tuttavia, quando si esegue l'aritmetica come addizione o sottrazione, si inizia con la fine.
1234
+ 0567
====
Si inizia con 4 e 7, si scrive la cifra più bassa e si ricorda il carry. Quindi aggiungi 3 e 6 ecc. Per aggiungere, sottrarre o confrontare, è più semplice da implementare, se hai già la logica per leggere la memoria in ordine, se i numeri sono invertiti.
Per supportare big endian in questo modo, è necessaria la logica per leggere la memoria al contrario, oppure si ha un processo RISC che funziona solo sui registri. ;)
Gran parte del design Intel x86 / Amd x64 è storico.
Il big-endian è utile per alcune operazioni (vengono in mente confronti di "bignum" di uguale lunghezza di ottetti). Little-endian per gli altri (aggiungendo due "bignum", possibilmente). Alla fine, dipende da cosa è stato impostato l'hardware della CPU, di solito è l'uno o l'altro (alcuni chip MIPS erano, IIRC, commutabili all'avvio per essere LE o BE).
Quando sono coinvolti solo l'archiviazione e il trasferimento con lunghezze variabili, ma nessuna aritmetica con più valori, allora LE è di solito più facile da scrivere, mentre BE è più facile da leggere.
Prendiamo una conversione da int a stringa (e ritorno) come esempio specifico.
int val_int = 841;
char val_str[] = "841";
Quando int viene convertito nella stringa, la cifra meno significativa è più facile da estrarre rispetto alla cifra più significativa. Tutto può essere fatto in un semplice ciclo con una semplice condizione finale.
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
Ora prova lo stesso nell'ordine BE. Di solito hai bisogno di un altro divisore che detenga la potenza maggiore di 10 per il numero specifico (qui 100). Devi prima trovare questo, ovviamente. Molte altre cose da fare.
La conversione da stringa a int è più semplice da eseguire in BE, quando viene eseguita come operazione di scrittura inversa. Scrivi memorizza l'ultima cifra più significativa, quindi dovrebbe essere letta per prima.
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');
}
Ora fai lo stesso in ordine LE. Ancora una volta, avresti bisogno di un fattore aggiuntivo che inizia con 1 e moltiplicato per 10 per ogni cifra.
Quindi di solito preferisco usare BE per l'archiviazione, perché un valore viene scritto esattamente una volta, ma letto almeno una volta e forse molte volte. Per la sua struttura più semplice, di solito vado anche sul percorso per convertire a LE e quindi invertire il risultato, anche se scrive il valore una seconda volta.
Un altro esempio di archiviazione BE sarebbe la codifica UTF-8 e molti altri.