LINUX

Aprenda Endianness y estructura de relleno en C

En este artículo, discutiremos el concepto de endianidad y relleno de estructura a través de ejemplos de C.

Aquí están los detalles del entorno de prueba:

  • SO – Ubuntu 13.04
  • Cascarón – Bash 4.2.45
  • Compilador – gcc (Ubuntu / Linaro 4.7.3-1ubuntu1) 4.7.3

Concepto de endianidad en el programa C

Endianidad del sistema

¿Alguna vez ha pensado en cómo se almacenan en la memoria los tipos de datos de varios bytes (como enteros, flotantes, etc.)? Bueno, si cree que un valor entero como 0x1234 (en hexadecimal) se almacena en la memoria como 12 34 entonces sólo está parcialmente en lo cierto. Debe comprender el concepto de endianidad para tener una mejor idea de cómo se almacenan los valores en la memoria.

En esta sección discutiremos los formatos de almacenamiento little-endian y big-endian.

Little Endian

En este formato, el último byte de un valor de tipo de datos multibyte se almacena primero y el primer byte se almacena en último lugar. Por ejemplo, el valor 0x1234 se almacena como:

34 12

Del mismo modo, el valor 0x12345678 se almacena como:

78 56 34 12

en máquinas little-endian.

Big Endian

En este formato, el byte inicial de un valor de tipo de datos multibyte se almacena primero y el byte final se almacena en último lugar. Por ejemplo, el valor 0x1234 se almacena como:

12 34

Del mismo modo, el valor 0x12345678 se almacena como:

12 34 56 78

en máquinas big-endian.

Si observa, verá que estos dos formatos de almacenamiento son exactamente opuestos entre sí.

¿Por qué es importante la endianidad?

Las máquinas almacenan valores de acuerdo con su endianidad. Por ejemplo, las máquinas IBM y DEC son little endian, mientras que las máquinas Sun y Motorola son big endian. Ahora, suponga que envía un archivo que contiene valores enteros desde un sistema big-endian a un sistema little-endian, definitivamente observará valores invertidos cuando intente leerlos en el sistema little-endian.

Debido a la existencia de ambos tipos de sistemas, el formato de datos de la red se mantiene fijo y siempre se transfiere en formato big-endian. Entonces, como programador, debe asegurarse de que los datos se lean en consecuencia.

¿Cómo determinar la endianidad de su máquina?

Aquí hay un programa a través del cual puede determinar fácilmente la endianidad de su máquina:

#include <stdio.h>

union u
{
short a;
char b;
}un;

int main(void)
{
un.a = 0xabcd;
if(un.b == 0xab)
printf("n The system is big-endiann");
else
printf("n The system is little-endiann");

return 0;
}

Entonces, en este programa, he declarado una unión de un entero corto y un carácter. En la función principal, se asigna un valor de 2 bytes al entero corto y luego se accede al primer byte a través del carácter ‘b’ (tanto las variables cortas como las char son parte de la unión y, por lo tanto, apuntan al mismo valor). Si el primer byte es 0xab, entonces el sistema es big-endian, de lo contrario, little-endian.

Cuando ejecuté este programa en mi máquina, la salida fue little endian:

$ ./endian

The system is little-endian

Entonces puede ver lo importante que es para los programadores comprender el concepto de endianidad del sistema.

Relleno de estructura

Antes de pasar a la explicación, consideremos un ejemplo:

#include<stdio.h>

struct st
{
char c;
int a;
}obj;

int main(void)
{
printf("n Size of structure is [%lu]n", sizeof (struct st));

return 0;
}

¿Cuál será el tamaño de la estructura según usted? ¿Está de acuerdo en que será sizeof (char) + sizeof (int) es decir, 1 + 4 = 5 bytes? Bueno, si tu respuesta es sí, me temo que estás equivocado.

Aquí está la salida cuando se ejecutó el programa en mi máquina:

$ ./padding

Size of structure is [8]

Entonces puede ver que el tamaño real es de 8 bytes. Pero, puede que se pregunte de dónde provienen los 3 bytes adicionales. Volvamos a esto más tarde.

Hablamos de los formatos de almacenamiento de datos en la última sección. También vale la pena comprender que cada tipo de datos en C / C ++ tiene sus propios requisitos de alineación. Por ejemplo, un valor de carácter está alineado en bytes, lo que significa que se puede almacenar en cualquier dirección. Un valor corto está alineado con 2 bytes, lo que significa que siempre se almacena en una dirección que es múltiplo de dos. En líneas similares, los valores enteros y dobles están alineados de 4 bytes y 8 bytes respectivamente.

Ahora, uno podría preguntarse, ¿cómo ayuda la alineación? Vea, la arquitectura de un procesador de computadora es tal que puede leer 4 bytes u 8 bytes de una vez (estoy hablando de procesadores de 32 bits y 64 bits aquí). Entonces, si hablamos de un procesador de 32 bits, será fácil para él leer información empaquetada en 4 bytes. Si un número entero no comienza en una dirección que es múltiplo de 4, causará problemas de rendimiento ya que el procesador tendrá que hacer varios ciclos para leer el valor entero.

Volviendo al ejemplo que discutimos anteriormente. La razón por la que se agregaron esos 3 bytes adicionales porque el compilador quería alinear el entero con una memoria de 4 bytes. Modifiquemos el mismo programa para imprimir las direcciones:

#include<stdio.h>

struct st
{
char c;
int a;
}obj;

int main(void)
{
printf("n Address of 'c' is [%lu] n", (long unsigned) &obj.c);
printf("n Address of 'a' is [%lu] n", (long unsigned) &obj.a);
printf("n Size of structure is [%lu]n", sizeof (struct st));

return 0;
}

Cuando se ejecutó el programa, se produjo la siguiente salida:

$ ./padding

Address of 'c' is [6295620]

Address of 'a' is [6295624]

Size of structure is [8]

Por lo tanto, puede ver que si la dirección 6295621 se hubiera asignado al número entero ‘a’, se habrían violado las reglas de alineación y el procesador no habría podido obtener el valor de una vez. Por lo tanto, el compilador agregó 3 bytes de relleno después de la dirección 6295620 y luego asignó memoria para el entero ‘a’ en la dirección 6295624, que es un múltiplo de 4.

Entonces, en pocas palabras, puede decodificar el relleno en cualquier estructura teniendo en cuenta el tipo de procesador (32 bits o 64 bits) y aplicando las reglas de alineación para cada tipo de datos.

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba
Cerrar