Ir para conteúdo

Endianness


Leandro Fróes

Posts Recomendados

Boa noite!!

Hoje estava lendo um dos artigos da coluna "Fundamentos da Computação Ofensiva" na revista da h2hc e me deparei com um trecho de código bem bacana, ele é bem simples e explica bastante coisa. Minha intenção aqui não é explicar ordenação de bytes, acho que o artigo explicou muito bem isso, vou apenas falar de uma única linha de código (de acordo com o meu entendimento) e como ela pode ser útil.

O código é esse aqui:

#include <stdio.h>

int main(){

  int x = 1;

  if(*(char *)&x == 1)
    printf("Little Endian!!\n");
  else
    printf("Big endian!!");

  return 0;
}
user@test:/home/codes# ./teste
Little Endian!!

 

A ideia é testar o endianness (ordenação) dos bytes. O que está rolando no código acima? Assumindo um inteiro de 32 bits atribuimos o valor 1 à ele. Dentro do condicional IF acontece a seguinte mágica: converte o endereço de x (que é de um inteiro) para o endereço de um char  e o operador * que precede o casting (char*) diz que estamos apontando para o conteúdo daquele endereço e SE o valor que estamos apontando for 1, é Little Endian. Pera, que? Blz, para entender a linguagem decidi fazer um código bem newbie pra mostrar números e ver o que está acontecendo no código acima:

 

#include <stdio.h>

int main(){

  int x = 1;
  printf("Valor de x: %d\n", x);

  int y = *(char *)&x;
  printf("Valor de y: %d\n", y);

  char *p = (char *)&x;
  printf("Valor apontado por p: %d\n", *p);


  return 0;
}

 

user@test:/home/codes# ./teste
Valor de x: 1
Valor de y: 1
Valor apontado por p: 1

O que podemos notar aqui (assumindo de fato que é little endian) é que na declaração do ponteiro para char p que toda essa mágica é meramente um casting no endereço da variável. Note que em y fiz toda a linha do código e o valor deu realmente 1, mas em p tirei o primeiro * e mantive apenas o casting de fato, com isso imprimi o valor apontado pelo ponteiro p que recebeu o endereço com o casting e deu 1 também!!

Ok, mas até agora não entendi o endianness. A sacada é que se for Little Endian os bits no endereço de x estariam dessa forma: 00000000 00000000 00000000 00000001, com o casting do endereço para um tipo char nós limitamos o teste para apenas a célula da direta e SE esta célula de oito bits possuir o valor 1 (que é o caso) será little endian, pois neste os bytes menos significativos são codificados primeiro. Caso neste teste o valor seja diferente de 1 (no caso zero) é porque é Big Endian pois neste os bytes mais significativos (da esquerda) são codificados primeiro.

Esse assunto deve ser bem simples pra maioria de vocês, mas eu curto ler sobre coisas simples e ver o quão essenciais são, espero não ter sido confuso e me corrijam qualquer besteira que escrevi. Caso tenha uma visão diferente por favor, me dê um toque, gostaria de saber mais sobre.

Abs!!

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Interessante. A convenção little começa pelo menos significativo (começa pelo menor, little) e o outro pelo mais significativo  (começa pelo maior, big). Do menor endereço até o maior. 

E como os dados ficam nos registradores? Veja uma explicação na internet:

Citar

The only time endianness matters is when you look at the value as bytes, 
not as dwords.  0FFEEDDCCh is always going to load as 0FFEEDDCCh, but they 
are stored in memory differently.  Consider this data in memory: 

  00004000:   00 11 22 33 44 55 66 77 

On a little-endian processor, if you load that into a 32-bit register, you 
get this: 
    mov  eax, [4000h]    ; 0x33221100 

But if I do the same operation on a big-endian processor: 
    ldr  r3, #0x4000     ; 0x00112233 

With that same piece of memory, notice the differences: 

                    Little         Big 
    Load byte           00          00 
    Load word         1100        0011 
    Load dword    33221100    00112233 
-- 
Tim Roberts, ti...@probo.com 
Providenza & Boekelheide, Inc. 

Se alguém quiser comentar mais alguma coisa para esclarecer mais o assunto será bem vindo.

Link para o comentário
Compartilhar em outros sites

No GCC, se quiser testar pelo "endianess" para garantir que seu código funcionará corretamente (se tentar obter frações de dados maiores), pode usar:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
...
#else
...
#endif

Essas são umas das muitas definições padrão do GCC, que podem ser vistas com:

$ gcc -dM -E - < /dev/null | less

[]s
Fred

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...