Little Endian vs Big Endian en C

Little Endian vs Big Endian en C

En este tutorial, discutiremos el concepto de endianness en la computadora. Endian significa ordenar byte. Dos tipos de endianness están presentes en la computadora: Big India y Little Indian. Cuando los datos se almacenan en la memoria, los bits se almacenan byte por byte en byte. Byte es una unidad de datos de memoria que consisten en un grupo de 8 bits. La memoria de la computadora es de dirección de byte, por lo que solo un byte puede estar presente dentro de la ubicación de la memoria. Cuando los datos son solo un byte, este byte se almacena en una sola ubicación de memoria. Pero cuando los datos son más de un byte, estos bytes pueden almacenarse en la ubicación de la memoria de dos maneras diferentes.

Ejemplos para entender:

int x = 513;

La representación binaria de dos bytes de 513 es 0000001000000001.

MSB LSB
00000010 00000001

La memoria es byte direccionable. Un byte se almacena en una ubicación de memoria y esta ubicación de memoria tiene una dirección. Si un byte se almacena en la dirección "A", el siguiente byte se almacena en la siguiente dirección que es "A+1", y así sucesivamente. Ahora, los bytes se pueden almacenar en la memoria desde los bytes más izquierdos hasta los bytes más derecho o desde los bytes más derecho hasta los bytes más izquierdos.

Aquí, la dirección de memoria inicial es "A". Entonces, si los bytes se almacenan en la memoria de los bytes más izquierdos a los bytes más derecho, el byte más izquierdo "00000010"Se almacena en la ubicación de memoria" A "y en el byte más correcto"00000001"Se almacena en la ubicación de la memoria" A+1 ".

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

¿Qué es Big Endian??

Cuando el byte más significativo está presente en la ubicación de memoria más pequeña, el siguiente byte se almacena en la siguiente dirección de memoria, y así sucesivamente. Este tipo de orden de byte se llama "Big Endian".

Si los bytes se almacenan en la memoria desde los bytes más derecho a los bytes más izquierdos, el byte más derecho "00000001"Se almacena en la ubicación de la memoria" A "y el byte más izquierdo"00000010"Se almacena en la ubicación de la memoria" A+1 ".

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

Que es el pequeño endian?

Cuando se almacena el byte menos significativo en la ubicación de memoria más pequeña, el byte anterior se almacena en la siguiente dirección de memoria, y así sucesivamente. Este tipo de orden de byte se llama "pequeño endian".

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

Podemos verificar si una computadora es Big Endian o Little Endian usando los siguientes ejemplos de código C:

Ejemplo 1:

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

int main ()
printf ("máquina endianness =>");
endian ();
regresar 0;

Producción:

somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ gcc ejemplo1.C -O Ejemplo1
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ ./Ejemplo 1
Machine Endianness => Little Endian
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $

Aquí, si el entero es dos bytes, la representación binaria de 1 es 00000000 00000001. Convertimos el puntero a un puntero de char que es un byte largo. Entonces, si accedemos a la primera ubicación de memoria y obtenemos el valor de 1, significa que el byte más correcto se almacena en la ubicación de memoria más baja. Entonces es una pequeña máquina endian. De lo contrario, será una gran máquina endian.

Ejemplo 2:

#incluir
Union Endian
int i;
char c [sizeof (int)];
;
int main ()
Union Endian u;
u.i = 1;
si tu.C [0] == 1)
printf ("Little Endian \ n");
demás
printf ("Big Endian \ n");
regresar 0;

Producción:

somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ gcc ejemplo2.C -O Ejemplo2
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ ./Ejemplo2
Little Endian
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $

En este ejemplo, usamos Union. Si 1 se almacena en el 0th Ubicación de la matriz, la máquina debe ser pequeña endian. De lo contrario, la máquina será Big Endian.

Problema en la endianness

Una computadora almacena y recupera los datos en la misma endianness en la que el resultado es el mismo. El problema surge en la endianness cuando los datos transfieren de una máquina a otra máquina. Si las dos máquinas están en sexo de byte diferente, significa que una computadora usa el Big Endian y otra computadora usa el Little Endian. Cuando los datos se transfieren de uno a otro, surgen los problemas reales. Este problema se llama problema nuxi: la cadena "unix" puede parecerse a "nuxi" en una máquina con un sexo de byte diferente.

Surge otro problema cuando usamos Typecast en nuestro programa. Por ejemplo: si creamos una matriz de caracteres de ARR [4] y la tipeamos a un INT de byte de tamaño 4, obtendremos diferentes resultados en una máquina endian diferente. Discutamos en el siguiente ejemplo.

Ejemplo 3:

#incluir
int main ()

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

Producción:

somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ gcc ejemplo3.C -O Ejemplo3
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ ./Ejemplo3
0x1
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $

En este ejemplo, "arr" es una matriz de personajes. Lo escribimos a un entero de 4 bytes x. Si compilamos el programa en una pequeña máquina endian, obtenemos el valor de 0x00000001. Pero si compilamos el programa en una gran máquina endian, obtenemos el valor de 0x01000000.

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

Ejemplo 4:

#incluir
int main ()

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

Producción:

somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ GCC Ejemplo4.C -O Ejemplo4
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ ./Ejemplo4
0x1000000
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $

Este ejemplo es el mismo que en el ejemplo 3. Solo cambie el valor para comprenderlo de manera más simple. Si compilamos el programa en una pequeña máquina endian, obtenemos el valor de 0x01000000. Pero si compilamos el programa en una gran máquina endian, obtenemos el valor de 0x00000001.

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

Cuando los datos se transfieren de una máquina endian a otra máquina de endian, necesitamos intercambiar los datos en consecuencia. Ahora, veamos cómo intercambiar los datos en los siguientes ejemplos.

Ejemplo 5:

En este ejemplo, usamos la operación bit a bit para intercambiar los datos. En la operación bit a bit, no hay efecto de endianness.

#incluir
#incluir
uint32_t byteswap (valor uint32_t)

uint32_t resultado = 0;
resultado = resultado | (valor y 0x000000ff) << 24;
resultado = resultado | (valor y 0x0000ff00) << 8;
resultado = resultado | (valor y 0x00ff0000) >> 8;
resultado = resultado | (valor y 0xff000000) >> 24;
resultado de retorno;

int main ()

uint32_t data = 0x44445555;
uint32_t resultData = 0;
resultData = byteswap (datos);
printf ("data original => 0x%x \ n", datos);
printf ("Datos convertidos => 0x%x \ n", ResultData);
regresar 0;

Producción:

somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ gcc ejemplo3.C -O Ejemplo3
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ ./Ejemplo3
Datos originales => 0x44445555
Datos convertidos => 0x55554444
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $

Ejemplo 6:

En este ejemplo, haremos lo mismo que en el ejemplo 5. Pero aquí, usamos macros en lugar de función.

#incluir
#incluir
#define Change_endianness (a) (((((uint32_t) (a) y 0xff000000) >> 24) \

| ((((uint32_t) (a) y 0x00ff0000) >> 8) \
| ((((uint32_t) (a) y 0x0000ff00) << 8) \
| ((((uint32_t) (a) y 0x000000ff) << 24))
int main ()
uint32_t data = 0x44445555;
uint32_t resultData = 0;
resultData = Change_endianness (datos);
printf ("data original => 0x%x \ n", datos);
printf ("Datos convertidos => 0x%x \ n", ResultData);
regresar 0;

Producción:

somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ GCC Ejemplo66.C -O Ejemplo6
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ ./Ejemplo6
Datos originales => 0x44445555
Datos convertidos => 0x55554444
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $

Ejemplo 7:

En este ejemplo, haremos lo mismo que lo hicimos en el ejemplo anterior. Pero aquí, usamos Union.

#incluir
#incluir
TypeDef Union

uint32_t rawdata;
uint8_t databuff [4];
RawData;
uint32_t Change_endianness (valor uint32_t)

Cambio de Data Raw, orginal;
Orginal.u32rawData = valor;
// Cambiar el valor
Cambiar.DataBuff [0] = Orginal.DataBuff [3];
Cambiar.DataBuff [1] = Orginal.DataBuff [2];
Cambiar.DataBuff [2] = Orginal.DataBuff [1];
Cambiar.DataBuff [3] = Orginal.DataBuff [0];
regresar (cambiar.RawData);

int main ()
uint32_t data = 0x44445555;
uint32_t resultData = 0;
resultData = Change_endianness (datos);
printf ("data original => 0x%x \ n", datos);
printf ("Datos convertidos => 0x%x \ n", ResultData);
regresar 0;

Producción:

somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ GCC Ejemplo55.C -O Ejemplo5
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $ ./Ejemplo5
Datos originales => 0x44445555
Datos convertidos => 0x55554444
somnath@somnath-virtualbox: ~/escritorio/c_prog/endian $

Cuando enviamos los datos a través de la red, los datos se envían en un formato común. Cuando los datos se envían a través de la red, no conocemos la endianness del remitente y el receptor. Entonces, usamos un pedido especial que es Big Endian. Este orden se llama "orden de red".

Si el remitente es una pequeña máquina endian, convierte los datos en un gran pedido de endian antes de enviar los datos. Si el receptor es una pequeña máquina endian, convierte los datos en un pequeño formato de endian después de recibir los datos.

Cuando enviamos los datos a la red, se utilizan las siguientes macros:

htons () - "Host a Red Short"

Htonl () - "Host a Red Long"

NTOHS () - "Red para alojar corta"

NTOHL () - "Red para alojar mucho"

htons () - Esta macro se lee como "host a red corta". Los bytes de un valor no firmado de 16 bits deben reorganizarse como lo siguiente:

Orden de procesador -> Orden de red.

htonl () - Esta macro se lee como "host a la red larga". Los bytes de un valor no firmado de 32 bits deben reorganizarse como lo siguiente:

Orden de procesador -> Orden de red.

NTOHS () - Esta macro se lee como "red para alojar corta". Los bytes de un valor no firmado de 16 bits deben reorganizarse como lo siguiente:

Orden de red -> Orden de procesador.

ntohl () - Esta macro se lee como "red para alojar larga". Los bytes de un valor no firmado de 32 bits deben reorganizarse como lo siguiente:

Orden de red -> Orden de procesador.

Conclusión

En este tutorial, aprendimos los detalles sobre la endianness en la computadora. Parece que utilizar un enfoque de endianness sobre el otro no tiene ventaja. Ambos todavía son utilizados por varias arquitecturas. La mayoría de las computadoras personales y las computadoras portátiles emplean hoy las CPU (y sus clones) con sede en Little Endian, lo que hace que el pequeño endian sea la arquitectura predominante para las computadoras de escritorio.