Tabla de fichas Indice del Tema 0203
0201 0202 0203 0204 0205 0206 0207 0208

UNIONES EN C







Definición, declaración e iniciación de uniones.
Por definición, una variable es un segmento de memoria caracterizado por su dirección de comienzo, extensión e interpretación. Ya se ha estudiado el concepto de estructura: una colección de variables que ocupan posiciones más o menos contiguas (recuerdese el problema de los espacios de relleno). También se ha estudiado el concepto de campos de bits. Pues bien, una unión es el análogo de una estructura, salvo por un detalle: todos los campos de que consta una estructura comienzan en una misma posición, que es la dirección de comienzo de la estructura. Consiguientemente, las uniones tienen una longitud que es precisamente la del mayor de sus campos. Dicho de otro modo, una unión es una estructura en que todos los campos están superpuestos, ocupando la misma porción de memoria física. Si algunos campos son más cortos y otros más largos, el aprovechamiento real de memoria puede no ser total. Desde el punto de vista

Campos de bits.
La definición de campos de bits en uniones es análoga a su contrapartida en estructuras (q.v.). Tal como se indicara entonces, el uso de campos de bits permite estudiar la estructura interna (binaria) de los tipos de datos en C. Véase a continuación un ejercicio que va a mostrar la codificación utilizada para distintos tipos de datos; el usuario puede insertar el valor que le parezca oportuno, y el programa responde con la estructura de bits asociada. Hay que tener especialmente en cuenta el esquema de almacenamiento de bytes que emplean las arquitecturas "Little-endian" y "Big-endian"; en este sentido, el ejercicio más ilustrativo puede ser estudiar la codificación de un número entero (como el 1) en ambos tipos de procesadores. En este sentido, véase el siguiente Ejercicio.

Campos de relleno.
Siguen teniendo el mismo sentido que en las estructuras: una forma de optimizar el tiempo de acceso. Su único efecto es que la alineación de campos individuales coincida con los límites de una palabra. De este modo se consigue acceder directamente al contenido de la variable en cuestión, sin necesidad de reordenar los bytes para descartar el relleno. Esto supone una mayor velocidad de procesamiento.

Estructura interna.


Esta es la disposición en memoria de una struct con tres campos: un int, un float y un muchos_bits formado por 32 bits.


Cada campo ocupa una zona de memoria independiente.

Esta es la disposición en memoria de una union que está formada por los mismos campos que la struct que se muestra a la izquierda.


Los campos están superpuestos en memoria.


Esto implica que la información que contiene la unión puede interpretarse con tantos tipos como campos, aunque la trama exacta de bits sea siempre la misma. De este modo, empleando una colección de campos de bits, se puede estudiar la reprentación interna de la información almacenada a través de los otros campos.

Ejercicio.- Construir un programa que permita observar la estructura de bits de un entero (de 4 bytes) y de un float.

#include<stdio.h>

/*
 Este programa muestra la estructura de bits de un entero
 y de un real.
*/

struct muchos_bits {
 unsigned bit1:1;
 unsigned bit2:1;
 unsigned bit3:1;
 unsigned bit4:1;
 unsigned bit5:1;
 unsigned bit6:1;
 unsigned bit7:1;
 unsigned bit8:1;
 unsigned bit9:1;
 unsigned bit10:1;
 unsigned bit11:1;
 unsigned bit12:1;
 unsigned bit13:1;
 unsigned bit14:1;
 unsigned bit15:1;
 unsigned bit16:1;
 unsigned bit17:1;
 unsigned bit18:1;
 unsigned bit19:1;
 unsigned bit20:1;
 unsigned bit21:1;
 unsigned bit22:1;
 unsigned bit23:1;
 unsigned bit24:1;
 unsigned bit25:1;
 unsigned bit26:1;
 unsigned bit27:1;
 unsigned bit28:1;
 unsigned bit29:1;
 unsigned bit30:1;
 unsigned bit31:1;
 unsigned bit32:1;
};

union Ejemplo_union {
 int entero_union;
 float float_union;
 struct muchos_bits bits_union;
} union_prueba;

 int entero_prueba;
 float float_prueba;
void main(void)
{
 printf("Programa de prueba para uniones, enteros y reales.\n\n");
 
 printf("Escriba el valor de un entero: ");
 scanf("%d", &entero_prueba);
 
 union_prueba.entero_union = entero_prueba;
 
 printf("\nLo que sigue es la estructura de bits del entero:\n\n");
/*
 printf("@primer bit: %ld\n",&(union_prueba.bits_union.bit1));
 printf("@noveno bit: %ld\n",&(union_prueba.bits_union.bit9));
 printf("@decimoseptimo bit: %ld\n",&(union_prueba.bits_union.bit17));
 printf("@vigesimoquinto bit: %ld\n\n",&(union_prueba.bits_union.bit25));
*/
 printf("%d",union_prueba.bits_union.bit1);
 printf("%d",union_prueba.bits_union.bit2);
 printf("%d",union_prueba.bits_union.bit3);
 printf("%d",union_prueba.bits_union.bit4);
 printf("%d",union_prueba.bits_union.bit5);
 printf("%d",union_prueba.bits_union.bit6);
 printf("%d",union_prueba.bits_union.bit7);
 printf("%d",union_prueba.bits_union.bit8);
 printf("%d",union_prueba.bits_union.bit9);
 printf("%d",union_prueba.bits_union.bit10);
 printf("%d",union_prueba.bits_union.bit11);
 printf("%d",union_prueba.bits_union.bit12);
 printf("%d",union_prueba.bits_union.bit13);
 printf("%d",union_prueba.bits_union.bit14);
 printf("%d",union_prueba.bits_union.bit15);
 printf("%d",union_prueba.bits_union.bit16);
 printf("%d",union_prueba.bits_union.bit17);
 printf("%d",union_prueba.bits_union.bit18);
 printf("%d",union_prueba.bits_union.bit19);
 printf("%d",union_prueba.bits_union.bit20);
 printf("%d",union_prueba.bits_union.bit21);
 printf("%d",union_prueba.bits_union.bit22);
 printf("%d",union_prueba.bits_union.bit23);
 printf("%d",union_prueba.bits_union.bit24);
 printf("%d",union_prueba.bits_union.bit25);
 printf("%d",union_prueba.bits_union.bit26);
 printf("%d",union_prueba.bits_union.bit27);
 printf("%d",union_prueba.bits_union.bit28);
 printf("%d",union_prueba.bits_union.bit29);
 printf("%d",union_prueba.bits_union.bit30);
 printf("%d",union_prueba.bits_union.bit31);
 printf("%d",union_prueba.bits_union.bit32);
 
 printf("\n\nEscriba el valor de un float: ");
 scanf("%f", &float_prueba);
 
 union_prueba.float_union = float_prueba;
 
 printf("\nLo que sigue es la estructura de bits del float:\n\n");

 printf("%d",union_prueba.bits_union.bit1);
 printf("%d",union_prueba.bits_union.bit2);
 printf("%d",union_prueba.bits_union.bit3);
 printf("%d",union_prueba.bits_union.bit4);
 printf("%d",union_prueba.bits_union.bit5);
 printf("%d",union_prueba.bits_union.bit6);
 printf("%d",union_prueba.bits_union.bit7);
 printf("%d",union_prueba.bits_union.bit8);
 printf("%d",union_prueba.bits_union.bit9);
 printf("%d",union_prueba.bits_union.bit10);
 printf("%d",union_prueba.bits_union.bit11);
 printf("%d",union_prueba.bits_union.bit12);
 printf("%d",union_prueba.bits_union.bit13);
 printf("%d",union_prueba.bits_union.bit14);
 printf("%d",union_prueba.bits_union.bit15);
 printf("%d",union_prueba.bits_union.bit16);
 printf("%d",union_prueba.bits_union.bit17);
 printf("%d",union_prueba.bits_union.bit18);
 printf("%d",union_prueba.bits_union.bit19);
 printf("%d",union_prueba.bits_union.bit20);
 printf("%d",union_prueba.bits_union.bit21);
 printf("%d",union_prueba.bits_union.bit22);
 printf("%d",union_prueba.bits_union.bit23);
 printf("%d",union_prueba.bits_union.bit24);
 printf("%d",union_prueba.bits_union.bit25);
 printf("%d",union_prueba.bits_union.bit26);
 printf("%d",union_prueba.bits_union.bit27);
 printf("%d",union_prueba.bits_union.bit28);
 printf("%d",union_prueba.bits_union.bit29);
 printf("%d",union_prueba.bits_union.bit30);
 printf("%d",union_prueba.bits_union.bit31);
 printf("%d",union_prueba.bits_union.bit32);
 printf("\n\nTerminación normal del programa.\n");
}
/*
Programa de prueba para uniones, enteros y reales.

Escriba el valor de un entero: 1

Lo que sigue es la estructura de bits del entero:

00000000000000000000000000000001

Escriba el valor de un float: 1

Lo que sigue es la estructura de bits del float:

00111111100000000000000000000000

Terminación normal del programa.

*/

Comentario.- Este programa puede reducirse algo empleando una sola sentencia printf con 32 especificadores de formato %d. Se deja como ejercicio para el lector. En una vena más sofisticada, se puede crear una máscara deslizante (con el operador << y un bucle for(), dando lugar a un código mucho más compacto. También es interesante emplear este programa para comprobar que los cálculos realizados a mano producen los mismos resultados que el ordenador.