Little Endian vs Big Endian em C

Little Endian vs Big Endian em C

Neste tutorial, discutiremos o conceito de Endianness no computador. Endian significa pedidos de byte. Dois tipos de endianness estão presentes no computador: Big Indian e Little Indian. Quando os dados são armazenados na memória, os bits são armazenados de byte por byte em byte. Byte é uma unidade de dados de memória que consiste em um grupo de 8 bits. A memória do computador é adiciável de byte, portanto, apenas um byte pode estar presente dentro do local da memória. Quando os dados são apenas um byte, este byte é armazenado em um único local de memória. Mas quando os dados são mais de um byte, esses bytes podem ser armazenados no local da memória de duas maneiras diferentes.

Exemplos para entender:

int x = 513;

Dois bytes Representação binária de 513 é 0000001000000001.

Msb LSB
00000010 00000001

A memória é endereçável byte. Um byte é armazenado em um local de memória e este local de memória tem um endereço. Se um byte for armazenado no endereço "A", o próximo byte será armazenado no próximo endereço que é "a+1" e assim por diante. Agora, os bytes podem ser armazenados na memória dos bytes mais à esquerda para os bytes mais à direita ou dos bytes mais à direita para os bytes mais à esquerda.

Aqui, o endereço de memória inicial é "a". Portanto, se os bytes forem armazenados na memória dos bytes mais à esquerda para os bytes mais à direita, o byte mais esquerdo “00000010"É armazenado no local da memória" A "e no byte mais à direita"00000001”É armazenado no local da memória“ A+1 ”.

A - 1
a 00000010
a + 1 00000001
a + 2

O que é grande endiano?

Quando o byte mais significativo está presente no menor local da memória, o próximo byte é armazenado no próximo endereço de memória e assim por diante. Este tipo de ordem de byte é chamado de "Big Endian".

Se os bytes forem armazenados na memória dos bytes mais à direita para os bytes mais à esquerda, o byte mais direito “00000001"É armazenado no local da memória" A "e no byte mais esquerdo"00000010”É armazenado no local da memória“ A+1 ”.

A - 1
a 00000001
a + 1 00000010
a + 2

O que é pequeno endian?

Quando o byte menos significativo é armazenado no menor local da memória, o byte anterior é armazenado no próximo endereço de memória e assim por diante. Este tipo de ordem de bytes é chamado de "Little Endian".

A - 1
a 00000010
a + 1 00000001
a + 2

Podemos verificar se um computador é Big Endian ou Little Endian usando os seguintes exemplos de código C:

Exemplo 1:

#incluir
void endian ()
int x = 1;
char *a = (char *) & x;
if (a [0] == 1)
printf ("Little Endian \ n");
outro
printf ("Big Endian \ n");

int main ()
printf ("Machine endianness =>");
endian ();
retornar 0;

Saída:

SOMNATH@SOMNATH-VIRTUALBOX: ~/Desktop/c_prog/endian $ gcc Exemplo1.C -O Exemplo1
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $ ./Exemplo 1
Máquina Endianness => Little Endian
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $

Aqui, se o número inteiro for dois bytes, a representação binária de 1 é 00000000 00000001. Convertemos o ponteiro para um ponteiro de Char, que é um byte de comprimento. Portanto, se acessarmos o primeiro local da memória e obtivermos o valor de 1, isso significa que o byte mais à direita é armazenado no local da memória mais baixa. É então uma pequena máquina endiana. Caso contrário, será uma grande máquina endiana.

Exemplo 2:

#incluir
Union Endian
int i;
char c [sizeof (int)];
;
int main ()
Union Endian U;
você.i = 1;
se você.c [0] == 1)
printf ("Little Endian \ n");
outro
printf ("Big Endian \ n");
retornar 0;

Saída:

SOMNATH@SOMNATH-VIRTUALBOX: ~/Desktop/c_prog/endian $ gcc Exemplo2.C -O Exemplo2
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $ ./Exemplo2
Pequeno endian
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $

Neste exemplo, usamos união. Se 1 for armazenado no 0º Localização da matriz, a máquina deve ser pequena Endian. Caso contrário, a máquina será grande endiana.

Problema em Endianness

Um computador armazena e recupera os dados na mesma endianidade em que o resultado é o mesmo. A questão surge em Endianness quando os dados transferem de uma máquina para outra máquina. Se as duas máquinas estiverem em sexo de byte diferente, significa que um computador usa o grande endian e outro computador usa o pequeno endian. Quando os dados transferem de um para outro, os problemas reais surgem. Este problema é chamado de problema nuxi: a sequência "Unix" pode parecer "Nuxi" em uma máquina com um sexo de byte diferente.

Outro problema surge quando usamos o TypeCast em nosso programa. Por exemplo: se criarmos uma matriz de caracteres de arr [4] e a digitam para um INT do tamanho 4 byte, teremos um resultado diferente em diferentes Endian Machine. Vamos discutir no próximo exemplo.

Exemplo 3:

#incluir
int main ()

char arr [4] = 0x01, 0x00,0x00,0x00;
int x = *(int *) arr;
printf ("0x%x \ n", x);
retornar 0;

Saída:

SOMNATH@SOMNATH-VIRTUALBOX: ~/Desktop/c_prog/endian $ gcc Exemplo3.C -O Exemplo3
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $ ./Exemplo3
0x1
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $

Neste exemplo, "arr" é uma matriz de personagens. Nós o digitamos para um número inteiro de 4 bytes x. Se compilarmos o programa em uma pequena máquina Endian, obtemos o valor de 0x00000001. Mas se compilarmos o programa em uma grande máquina Endian, obtemos o valor de 0x01000000.

0x01 0x00 0x00 0x00
arr [0] arr [1] arr [2] arr [3]

Exemplo 4:

#incluir
int main ()

char arr [4] = 0x00, 0x00,0x00,0x01;
int x = *(int *) arr;
printf ("0x%x \ n", x);
retornar 0;

Saída:

SOMNATH@SOMNATH-VIRTUALBOX: ~/Desktop/c_prog/endian $ gcc Exemplo4.C -O Exemplo4
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $ ./Exemplo4
0x1000000
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $

Este exemplo é o mesmo do Exemplo 3. Apenas mude o valor para entendê -lo de maneira mais simples. Se compilarmos o programa em uma pequena máquina Endian, obtemos o valor de 0x01000000. Mas se compilarmos o programa em uma grande máquina Endian, obtemos o valor de 0x00000001.

0x00 0x00 0x00 0x01
arr [0] arr [1] arr [2] arr [3]

Quando os dados são transferidos de uma máquina Endian para outra máquina Endian, precisamos trocar os dados de acordo. Agora, vamos ver como trocar os dados nos seguintes exemplos.

Exemplo 5:

Neste exemplo, usamos a operação bit a bit para trocar os dados. Na operação bitwise, não há efeito de endianness.

#incluir
#incluir
uint32_t byteswap (valor uint32_t)

UINT32_T Result = 0;
resultado = resultado | (Valor & 0x000000FF) << 24;
resultado = resultado | (Valor & 0x0000FF00) << 8;
resultado = resultado | (Valor & 0x00FF0000) >> 8;
resultado = resultado | (Valor & 0xff000000) >> 24;
resultado de retorno;

int main ()

uint32_t dados = 0x44445555;
uint32_t resultData = 0;
resultadodata = byteswap (dados);
printf ("dados originais => 0x%x \ n", dados);
printf ("dados convertidos => 0x%x \ n", resultadodata);
retornar 0;

Saída:

SOMNATH@SOMNATH-VIRTUALBOX: ~/Desktop/c_prog/endian $ gcc Exemplo3.C -O Exemplo3
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $ ./Exemplo3
Dados originais => 0x44455555
Dados convertidos => 0x55554444
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $

Exemplo 6:

Neste exemplo, faremos a mesma coisa que fizemos no Exemplo 5. Mas aqui, usamos macros em vez de função.

#incluir
#incluir
#Define Change_endianness (a) ((((uint32_t) (a) e 0xff000000) >> 24) \

| (((uint32_t) (a) e 0x00FF0000) >> 8) \
| (((uint32_t) (a) e 0x0000FF00) << 8) \
| (((uint32_t) (a) e 0x000000FF) << 24))
int main ()
uint32_t dados = 0x44445555;
uint32_t resultData = 0;
resultadodata = change_endianness (dados);
printf ("dados originais => 0x%x \ n", dados);
printf ("dados convertidos => 0x%x \ n", resultadodata);
retornar 0;

Saída:

SOMNATH@SOMNATH-VIRTUALBOX: ~/Desktop/c_prog/endian $ gcc Exemplo6.C -O Exemplo6
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $ ./Exemplo6
Dados originais => 0x44455555
Dados convertidos => 0x55554444
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $

Exemplo 7:

Neste exemplo, faremos a mesma coisa que fizemos no exemplo anterior. Mas aqui, usamos união.

#incluir
#incluir
União Typedef

uint32_t rawdata;
uint8_t banco de dados [4];
Dados não tratados;
uint32_t change_endianness (valor uint32_t)

Mudança RAWData, orginal;
Orginal.u32RawData = valor;
// altere o valor
Mudar.Banco de dados [0] = orginal.Banco de dados [3];
Mudar.Banco de dados [1] = orginal.Banco de dados [2];
Mudar.Banco de dados [2] = orginal.Banco de dados [1];
Mudar.Banco de dados [3] = orginal.Banco de dados [0];
retornar (altere.Dados não tratados);

int main ()
uint32_t dados = 0x44445555;
uint32_t resultData = 0;
resultadodata = change_endianness (dados);
printf ("dados originais => 0x%x \ n", dados);
printf ("dados convertidos => 0x%x \ n", resultadodata);
retornar 0;

Saída:

SOMNATH@SOMNATH-VIRTUALBOX: ~/Desktop/c_prog/endian $ gcc Exemplo5.C -O Exemplo5
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $ ./Exemplo5
Dados originais => 0x44455555
Dados convertidos => 0x55554444
Somnath@Somnath-virtualBox: ~/Desktop/c_prog/endian $

Quando enviamos os dados pela rede, os dados são enviados em um formato comum. Quando os dados são enviados pela rede, não sabemos a endianidade do remetente e do receptor. Então, usamos um pedido especial que é grande endiano. Este pedido é chamado de "pedido de rede".

Se o remetente for uma pequena máquina endiana, ele converte os dados em um grande pedido Endian antes de enviar os dados. Se o receptor for uma pequena máquina endiana, ele converte os dados em um pequeno formato endiano depois de receber os dados.

Quando enviamos os dados para a rede, as seguintes macros são usadas:

htons () - “Host à rede curta”

Htonl () - “Host à rede Long”

NTOHS () - “Rede para hospedar curto”

NTOHL () - “Rede para hospedar Long”

htons () - Esta macro é lida como "host à rede curta". Os bytes de um valor não assinado de 16 bits devem ser reorganizados como o seguinte:

Ordem do processador -> Pedido de rede.

htonl () - Esta macro é lida como "host à rede longa". Um valor de um valor não assinado de 32 bits deve ser reorganizado como o seguinte:

Ordem do processador -> Pedido de rede.

Ntohs () - Esta macro é lida como "rede para hospedar curta". Os bytes de um valor não assinado de 16 bits devem ser reorganizados como o seguinte:

Pedido de rede -> Pedido do processador.

Ntohl () - Esta macro é lida como "rede para hospedar longa". Um valor de um valor não assinado de 32 bits deve ser reorganizado como o seguinte:

Pedido de rede -> Pedido do processador.

Conclusão

Neste tutorial, aprendemos os detalhes sobre Endianness no computador. Parece que a utilização de uma abordagem de Endianness sobre a outra não tem vantagem. Ambos ainda são utilizados por várias arquiteturas. A maioria dos computadores e laptops pessoais emprega hoje as CPUs pouco endianas (e seus clones), tornando o pequeno Endiano como a arquitetura predominante para computadores de desktop.