Qual è il vantaggio del formato little endian?


140

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?


1
Il 6502 era un primo (il primo?) Processore pipeline. Mi sembra di ricordare alcune affermazioni sul fatto che fosse poco endian per qualche problema relativo alle prestazioni dovuto alla pipeline - ma ora non ho idea di quale potrebbe essere stato quel problema. Eventuali suggerimenti?
Steve314,

1
@ Steve314: La mia risposta spiega come il piccolo endian aiuta con le prestazioni in una CPU pipeline: programmers.stackexchange.com/q/95854/27874
Martin Vilcans

3
Little-endian, big-endian: devi scegliere l'uno o l'altro. Come guidare sul lato sinistro o destro della strada.

3
Ti consiglio di scrivere del codice in ASM, preferibilmente per un'architettura "vecchia scuola" come 6502 o Z80. Vedrai immediatamente perché usano little endian. Le architetture che usano il big endian hanno determinate caratteristiche nel loro set di istruzioni che rendono preferibile quel formato. Non è una decisione arbitraria da prendere!
Stefan Paul Noack,

2
Ogni sistema di ordine byte ha i suoi vantaggi. Le macchine little-endian ti consentono di leggere prima il byte più basso, senza leggere gli altri. Puoi controllare se un numero è pari o dispari (l'ultimo bit è 0) molto facilmente, il che è bello se ti piace quel tipo di cose. I sistemi big-endian archiviano i dati nella memoria nello stesso modo in cui noi umani pensiamo ai dati (da sinistra a destra), il che semplifica il debug a basso livello.
Koray Tugay,

Risposte:


198

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".


3
Supponendo, ovviamente, che i byte di alto ordine che non hai letto possano essere ragionevolmente ignorati (ad esempio, sai che sono comunque zero).
Steve314,

10
@ Steve314: se eseguo il downcasting in C da 32 a 16 bit (ad es.) Su un sistema a complemento a 2 - la stragrande maggioranza dei sistemi - i byte non devono essere zero per essere ignorati. Indipendentemente dal loro valore, posso ignorarli e rimanere conforme allo standard C e alle aspettative del programmatore.

9
@Stritzinger - stiamo parlando del codice assembly / machine generato da un compilatore, che non può essere portatile. Il codice linguistico di livello superiore da compilare è portatile - si compila solo per diverse operazioni sulle diverse architetture (come fanno tutte le operazioni).
jimwise il

7
Non compro questo argomento, perché sulle architetture big-endian, un puntatore potrebbe puntare alla fine, piuttosto che all'inizio, di qualunque cosa ti riferisca e che avresti esattamente lo stesso vantaggio.
dan_waterworth,

4
@dan_waterworth non del tutto - tieni a mente le regole aritmetiche del puntatore in C, per esempio, e cosa succede quando aumenti o diminuisci i cast dello stesso puntatore. Puoi spostare la complessità, ma non puoi eliminarla.
jimwise,

45

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 ...

  1. Stai leggendo i valori sullo schermo o sulla carta.
  2. Metti gli indirizzi di memoria inferiori a sinistra e quelli superiori a destra.
  3. Stai scrivendo in esadecimale, con il nybble di alto ordine a sinistra, o binario, con il bit più significativo a sinistra.
  4. Hai letto da sinistra a destra.

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 ...

  • Il byte "più alto" (più significativo) dovrebbe essere all'indirizzo di memoria "più alto".

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.


30
I numeri sono infatti scritti da [cifra più significativa] da sinistra a [cifra meno significativa] a destra in arabo ed ebraico.
Casuale 832

5
Allora perché i bit all'interno di un byte sono memorizzati nel formato "big endian"? Perché non essere coerente?
tskuzzy,

11
Non lo sono: il bit 0 è per convenzione il meno significativo e il bit 7 il più significativo. Inoltre, generalmente non è possibile effettuare un ordine su bit all'interno di un byte, poiché i bit non sono indirizzabili individualmente. Naturalmente, potrebbero avere un ordine fisico in un determinato protocollo di comunicazione o supporto di archiviazione, ma a meno che non si lavori a livello di protocollo o hardware di basso livello, non è necessario preoccuparsi di questo ordine.
Stewart,

3
BlueRaja: solo per convenzione di scrivere su carta. Questo non ha nulla in comune con l'architettura della CPU. È possibile scrivere il byte come 0-7 LSB-MSB anziché 7-0 MSB-LSB e nulla cambia dal punto di vista dell'algoritmo.
SF.

2
@SF .: "Premi brevemente, fai scoppiare tutto tranne che corto " ti sorprenderà comunque. Anche se non stai corrompendo lo stack spingendo byte che non fai mai pop o viceversa ... x86 (32-bit), ad esempio, vuole davvero davvero che lo stack sia allineato a parole, e spingendo o saltando qualsiasi cosa che causa il il puntatore dello stack che non sia un multiplo di 4 può causare problemi di allineamento. E anche se non lo fosse, roba ha spinto un'intera parola / dword / qword / etc alla volta - quindi il byte basso sarà ancora il primo che otterrai quando fai il pop.
cHao,

41

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.


3
Ah - quindi è più o meno la stessa ragione per cui uso l'ordinamento di pezzi di little endian per numeri interi grandi. Avrei dovuto risolverlo. Le persone hanno davvero bisogno di lavorare sulla cibernetica ora - il mio cervello ha già un disperato bisogno di alcuni pezzi di ricambio e alcuni aggiornamenti radicali, non vedo l'ora per sempre!
Steve314,

2
Un pensiero - il 6502 non ha fatto molta matematica a 16 bit nell'hardware - era, dopo tutto, un processore a 8 bit. Ma ha fatto l'indirizzamento relativo, usando offset con segno a 8 bit relativi a un indirizzo base a 16 bit.
Steve314,

2
Nota che questa idea è ancora importante per l'aritmetica di interi a precisione multipla (come detto da Steve314), ma a livello di parola. Ora, la maggior parte delle operazioni non è direttamente influenzata dall'endianità del processore: si può ancora memorizzare prima la parola meno significativa su un sistema big-endian, come fatto da GMP. I processori little-endian presentano ancora un vantaggio per le poche operazioni (ad esempio alcune conversioni di stringhe?) Che potrebbero essere più facili da leggere leggendo un byte alla volta, poiché solo su un sistema little-endian, l'ordinamento dei byte di tali numeri è corretto.
vinc17,

i processori little-endian hanno un vantaggio nel caso in cui la larghezza di banda della memoria sia limitata, come in alcuni processori ARM a 32 bit con bus di memoria a 16 bit o 8088 con bus dati a 8 bit: il processore può semplicemente caricare la metà bassa e fare aggiungi / sub / mul ... con esso mentre aspetti la metà superiore
phuclv il

13

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)


1
Il big-endian è davvero più facile per gli umani perché non richiede la riorganizzazione dei byte. Ad esempio, su un PC, 0x12345678è memorizzato come 78 56 34 12mentre 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)-1swap. Un'altra opzione è leggerli sia in avanti che all'indietro (leggendo ogni byte in avanti, ma scansionando l'intero # indietro).
Synetech,

Centotredici sono o end-end-end, oppure big-endian con "tredici" essenzialmente una cifra non decimale. Quando precisiamo i numeri, ci sono alcune piccole deviazioni dalle convenzioni a base costante che usiamo per le cifre, ma una volta eliminati quei casi speciali il resto è big-endian - milioni prima di migliaia, migliaia prima di centinaia ecc.
Steve314

@ Synetech- fortunatamente il computer non deve preoccuparsi di come gli umani li leggono. È come affermare che il flash NAND è migliore perché no '
Martin Beckett,

1
@ Steve314, le parole dei numeri scritte non contano, è la lettura numerica che è ciò che usiamo quando programmiamo. Martin, nessun computer non deve preoccuparsi di come gli umani leggano i numeri, ma se è facile per loro leggerli, allora la programmazione (o altri lavori correlati) diventa più facile e alcuni difetti e bug possono essere ridotti o evitati.
Synetech,

@ steve314 E in danese "95" è pronunciato "fem halvfems" (cinque, più quattro e mezzo e venti).
Vatine,

7

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 memcmpper 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 ...

  1. 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.

  2. 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.


7

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 è:

  • Carica un byte dalla posizione di recupero
  • sposta quel byte a sinistra di 8 posizioni
  • incrementa la posizione di recupero della memoria di 1
  • carica il byte successivo (nella parte di ordine inferiore del registro)

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.)


3

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 :)


1
Ciò dimostra solo che è più veloce / più facile lavorare in qualsiasi formato nativo della CPU. Non dice nulla sul fatto che sia meglio. Lo stesso vale per big endian: for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }corrisponde a move.l data, numuna CPU big endian.
Martin Vilcans,

@martin: una sottrazione in meno è migliore nel mio libro
Cem Kalyoncu,

Non importa davvero perché il compilatore srotolerà comunque il loop. In ogni caso, molte CPU hanno istruzioni di scambio di byte per gestire questo problema.
Martin Vilcans,

Non sono d'accordo su Big Endian, farei {num << = 8; num | = data [i]; } almeno questo non deve calcolare il conteggio dei turni a sinistra usando mul
Hayri Uğur Koltuk il

@ali: il tuo codice eseguirà esattamente l'operazione che ho scritto e non funzionerà su big endian.
Cem Kalyoncu,

1

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.


0

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).


0

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.