Os processadores Intel (e talvez alguns outros) usam o formato little endian para armazenamento.
Eu sempre me pergunto por que alguém iria querer armazenar os bytes na ordem inversa. Esse formato tem vantagens sobre o formato big endian?
Os processadores Intel (e talvez alguns outros) usam o formato little endian para armazenamento.
Eu sempre me pergunto por que alguém iria querer armazenar os bytes na ordem inversa. Esse formato tem vantagens sobre o formato big endian?
Respostas:
Existem argumentos de qualquer maneira, mas um ponto é que, em um sistema little endian, o endereço de um determinado valor na memória, tomado como largura de 32, 16 ou 8 bits, é o mesmo.
Em outras palavras, se você tiver na memória um valor de dois bytes:
0x00f0 16
0x00f1 0
tomar esse '16' como um valor de 16 bits (c 'curto' na maioria dos sistemas de 32 bits) ou como um valor de 8 bits (geralmente c 'char') altera apenas a instrução de busca que você usa - não o endereço que você busca de.
Em um sistema big endian, com o exposto acima, é apresentado como:
0x00f0 0
0x00f1 16
você precisaria incrementar o ponteiro e, em seguida, executar a operação de busca mais estreita no novo valor.
Então, resumindo, 'em pequenos sistemas endianos, os elencos não são opcionais'.
Eu sempre me pergunto por que alguém iria querer armazenar os bytes na ordem inversa.
Big endian e little endian são apenas "ordem normal" e "ordem inversa" de uma perspectiva humana, e somente se tudo isso for verdade ...
Essas são todas as convenções humanas que não importam para a CPU. Se você mantivesse os itens 1 e 2 e virasse o número 3, o little-endian pareceria "perfeitamente natural" para as pessoas que lêem árabe ou hebraico, escritas da direita para a esquerda.
E existem outras convenções humanas que tornam o big endian algo antinatural, como ...
Quando eu estava programando principalmente 68K e PowerPC, considerava o big endian "certo" e o little endian "errado". Mas desde que venho fazendo mais trabalhos com ARM e Intel, me acostumei com o little-endian. Realmente não importa.
OK, aqui está o motivo, como eu já havia explicado: adição e subtração
Ao adicionar ou subtrair números de vários bytes, é necessário começar com o byte menos significativo. Se você estiver adicionando dois números de 16 bits, por exemplo, pode haver uma transferência do byte menos significativo para o byte mais significativo; portanto, você deve começar com o byte menos significativo para verificar se há uma transferência. Esse é o mesmo motivo pelo qual você inicia com o dígito mais à direita ao fazer a adição à mão. Você não pode começar da esquerda.
Considere um sistema de 8 bits que busca bytes seqüencialmente da memória. Se buscar primeiro o byte menos significativo , ele poderá começar a adição enquanto o byte mais significativo estiver sendo buscado na memória. Esse paralelismo é o motivo pelo qual o desempenho é melhor em little endian em sistemas. Se tivesse que esperar até que os dois bytes fossem buscados da memória ou buscá-los na ordem inversa, levaria mais tempo.
Isso ocorre em sistemas antigos de 8 bits. Em uma CPU moderna, duvido que a ordem dos bytes faça alguma diferença e usamos pouco endian apenas por razões históricas.
Com processadores de 8 bits, certamente era mais eficiente, era possível executar uma operação de 8 ou 16 bits sem a necessidade de código diferente e sem a necessidade de armazenar buffer em valores extras.
Ainda é melhor para algumas operações de adição se você estiver lidando com um byte de cada vez.
Mas não há razão para que big-endian seja mais natural - em inglês você usa treze (little endian) e vinte e três (big endian)
0x12345678
é armazenado como 78 56 34 12
em um sistema BE 12 34 56 78
(o byte 0 está à esquerda, o byte 3 está à direita). Observe como quanto maior o número (em termos de bits), mais trocas são necessárias; uma PALAVRA exigiria uma troca; um DWORD, dois passes (três swaps totais); um QWORD três passes (7 no total) e assim por diante. Ou seja, (bits/8)-1
swaps. Outra opção é lê-los tanto para a frente e para trás (lendo cada byte para a frente, mas a digitalização de todo o # para trás).
A convenção japonesa de datas é "big endian" - aaaa / mm / dd. Isso é útil para algoritmos de classificação, que podem usar uma comparação simples de cadeias com a regra usual de primeiro caractere é a mais significativa.
Algo semelhante se aplica aos números de big endian armazenados em um registro de campo mais significativo. A ordem de significância dos bytes nos campos corresponde à significância dos campos no registro; portanto, você pode usar a memcmp
para comparar registros, sem se importar se está comparando duas palavras longas, quatro palavras ou oito bytes separados.
Inverta a ordem de significância dos campos e você obtém a mesma vantagem, mas para números little-endian em vez de big-endian.
Isso tem muito pouco significado prático, é claro. Se sua plataforma é big-endian ou little-endian, você pode solicitar campos de registros para explorar esse truque, se realmente precisar. É apenas uma dor se você precisar escrever um código portátil .
Posso incluir também um link para o apelo clássico ...
http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt
EDITAR
Um pensamento extra. Certa vez, escrevi uma grande biblioteca inteira (para ver se eu podia) e, para isso, os pedaços de 32 bits de largura são armazenados em ordem little-endian, independentemente de como a plataforma ordena os bits desses pedaços. As razões foram ...
Muitos algoritmos simplesmente começam a funcionar no final menos significativo e desejam que esses fins sejam compatíveis. Por exemplo, além disso, os carregamentos propogam dígitos cada vez mais significativos, por isso faz sentido começar no final menos significativo.
Aumentar ou diminuir um valor significa apenas adicionar / remover pedaços no final - não é necessário mudar os pedaços para cima / para baixo. Ainda é necessário copiar devido à realocação da memória, mas não com frequência.
Isso não tem relevância óbvia para os processadores, é claro - até que as CPUs sejam feitas com suporte a números grandes de hardware, isso é puramente uma coisa de biblioteca.
Ninguém mais respondeu POR QUE isso pode ser feito, muitas coisas sobre consequências.
Considere um processador de 8 bits que pode carregar um único byte da memória em um determinado ciclo de clock.
Agora, se você deseja carregar um valor de 16 bits, digamos (digamos) no único e somente registrador de 16 bits que você possui - ou seja, no contador do programa, então uma maneira simples de fazer isso é:
o resultado: você apenas incrementa o local da busca, apenas carrega na parte inferior do seu registro mais amplo e precisa mudar de posição para a esquerda. (É claro que mudar para a direita é útil para outras operações, portanto, este é um pouco de um show paralelo.)
Uma conseqüência disso é que o material de 16 bits (byte duplo) é armazenado na ordem Most..Least. Ou seja, o endereço menor tem o byte mais significativo - tão grande endian.
Se você tentou carregar usando little endian, seria necessário carregar um byte na parte inferior do seu registro amplo, depois carregar o próximo byte em uma área intermediária, alterá-lo e colocá-lo na parte superior do seu registro mais amplo . Ou use um arranjo mais complexo de portas para poder carregar seletivamente no byte superior ou inferior.
O resultado de tentar se tornar um pouco endian é que você precisa de mais silício (interruptores e portas) ou mais operações.
Em outras palavras, em termos de ganhar dinheiro por dinheiro nos velhos tempos, você ganha mais dinheiro pela maior performance e pela menor área de silício.
Hoje em dia, essas considerações são irrelevantes, mas coisas como preenchimento de pipeline ainda podem ser um grande problema.
Quando se trata de escrever em preto e branco, a vida é frequentemente mais fácil quando se usa pouco endereçamento endian.
(E os processadores big endian tendem a ser big endian em termos de ordenação de bytes e pouco endian em termos de bits em bytes. Mas alguns processadores são estranhos e usarão a ordenação de bits big endian e a ordem de bytes. Isso torna a vida muito interessante para o designer h / w adicionando periféricos mapeados na memória, mas não tem outra conseqüência para o programador.)
jimwise fez um bom argumento. Há outro problema: no little endian, você pode fazer o seguinte:
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
Mais direto para programadores que não são afetados pela desvantagem óbvia de locais trocados na memória. Pessoalmente, acho que o big endian é inverso do que é natural :). 12 devem ser armazenados e escritos como 21 :)
for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }
corresponde a move.l data, num
uma CPU big endian.
Eu sempre me pergunto por que alguém iria querer armazenar os bytes na ordem inversa
Número decimal são escritos big endian. Também como você escreve em inglês Você começa com o dígito mais significativo e o próximo mais significativo com o menos mais significativo. por exemplo
1234
é mil duzentos e trinta e quatro.
É assim que o big endian às vezes é chamado de ordem natural.
Em little endian, esse número seria um, vinte, trezentos e quatro mil.
No entanto, quando você executa aritmética como adição ou subtração, começa com o fim.
1234
+ 0567
====
Você começa com 4 e 7, escreve o dígito mais baixo e lembre-se do transporte. Em seguida, adicione 3 e 6 etc. Para adicionar, subtrair ou comparar, é mais simples de implementar, se você já possui lógica para ler a memória em ordem, se os números forem revertidos.
Para oferecer suporte a big endian dessa maneira, você precisa de lógica para ler a memória em sentido inverso ou possui um processo RISC que opera apenas em registradores. ;)
Muito do design Intel x86 / Amd x64 é histórico.
O big endian é útil para algumas operações (comparações de "bignums" de molas iguais de octetos). Little-endian para outros (adicionando dois "bignums", possivelmente). No final, depende do que o hardware da CPU foi configurado, geralmente é um ou outro (alguns chips MIPS eram, IIRC, selecionáveis na inicialização para LE ou BE).
Quando apenas o armazenamento e a transferência com comprimentos variáveis estão envolvidos, mas não há aritmética com vários valores, o LE geralmente é mais fácil de escrever, enquanto o BE é mais fácil de ler.
Vamos dar uma conversão int-to-string (e voltar) como um exemplo específico.
int val_int = 841;
char val_str[] = "841";
Quando o int é convertido na string, o dígito menos significativo é mais fácil de extrair do que o dígito mais significativo. Tudo isso pode ser feito em um loop simples com uma condição final simples.
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
Agora tente o mesmo na ordem BE. Normalmente, você precisa de outro divisor que detenha a maior potência de 10 para o número específico (aqui 100). Você primeiro precisa encontrar isso, é claro. Muito mais coisas para fazer.
A conversão de string para int é mais fácil de fazer no BE, quando é feita como a operação de gravação reversa. Write armazena o dígito mais significativo por último, portanto, ele deve ser lido primeiro.
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');
}
Agora faça o mesmo na ordem LE. Novamente, você precisaria de um fator adicional, começando com 1 e multiplicado por 10 para cada dígito.
Portanto, eu geralmente prefiro usar o BE para armazenamento, porque um valor é escrito exatamente uma vez, mas lido pelo menos uma vez e talvez muitas vezes. Por sua estrutura mais simples, eu também costumo seguir a rota para converter para LE e reverter o resultado, mesmo que ele grave o valor uma segunda vez.
Outro exemplo de armazenamento BE seria a codificação UTF-8 e muito mais.