En los títulos y los textos vais a encontrar unas cuantas citaciones cinematográficas (y si, soy un cinéfilo). Si no os interesan podéis fingir no verlas, ya que no son fundamentales para la comprensión de los post...

Este blog es la versión en Español de mi blog en Italiano L'arte della programmazione in C. Espero que mis traducciones sean comprensibles...

miércoles, 16 de octubre de 2013

La union hace la fuerza
cómo usar las union en C

Que levante la mano quien ha escrito recientemente código que utiliza las union. O bien, levante la mano, sin antes ir a volver a leer un manual de C, aquellos de vosotros que saben cómo usar y/o describir perfectamente las union ? Uhmm ... Veo pocas manos levantadas. El hecho es que la union es una de las partes del C menos conocida, de uso dudoso y poco frecuente, en definitiva, una de las partes que, por falta de práctica, se olvida.

Para introducir el tema (y , repito, sin consultar antes un manual de C, de lo contrario no os váis a poner a prueba), os voy a contar una historia real. Un tipo que conozco, cuyas iniciales son A.A. (no puedo decir más por privacidad) fue, hace mucho tiempo, a una entrevista de trabajo, y le propusieron una  simple test como este (más o menos):

#include <stdio.h>

void main(void)
{
    union u_test {
        int  i;
        char s[4];
    } my_test;

    my_test.i = 0x01020304;

    // que imprime la linea siguiente?
    printf("s[0]=%d s[1]=%d s[2]=%d s[3]=%d\n",
        my_test.s[0], my_test.s[1], my_test.s[2], my_test.s[3]);
}
En este caso, por las razones mencionadas al principio del post (uso dudoso y poco frecuente), nuestro amigo que no utilizaba una unión por lo menos desde hace 15 años (sí, 15 años !), se sorprendió al principio, luego forzó la memoria y no cae en el primer nivel de error que induce este test un poco engañoso, primero nivel de error que te llevaría a decir:

He inicializado el campo i y voy a leer el campo s: entonces la printf() imprime valores no definidos!

No, él se recordó que "las union asignan memoria para la mayor de las variables internas, variables que comparten el mismo espacio de memoria", y no cayó en la trampa, y respondió casi a la perfección... casi, porque cae el segundo nivel de error, el que te hace decir:

He inicializado i, pero leo s, que es como si hubiera sido inicializado, entonces la respuesta es : s[0]=1 s[1]=2 s[2]=3 s[3]=4 !

Ok, casi justo: de hecho, la respuesta es:

s[0]=4 s[1]=3 s[2]=2 s[3]=1

Nuestro amigo A.A. se dio cuenta de eso volviendo a casa, cuando ya se había hecho el error: en la ubicación s[0] termina la parte menos significativa de i (entonces 0x04), y así sucesivamente con los otros números, por lo que el resultado fue en orden inverso. Bueno, cosas que pasan...

Si buscáis en la red con google váis a encontrar muchos útiles ejemplos de uso de la union, entre los cuales, yo diría, los más interesantes son los para el tratamiento de datos con contenido variable (protocolos de comunicación, por ejemplo) con los cuales se quiere tratar, con la misma estructura de datos, información de diferente tipo, y interpretando la union, cada vez, en la forma correcta mediante la selección de un oportuno flag mantenido por el programa. Esto permite hacer programas flexibles y económicos en términos de memoria (en comparación con el uso de las struct), que en algunos entornos de desarrollo podrían ser útiles.

Ojo, sin embargo: por el modo mismo en que funcionan las union son flexibles pero engañosas, y los errores imprevistos de funcionamiento están detrás de la esquina esperando. Hay que ser muy estricto en el mantener, y testear, el flag de estado que nos indica cual personalidad de la union estamos utilizando en cada momento.

Hasta el próximo post.

Este post está inspirado en una historia real, pero cualquier parecido con hechos o personas reales es mera coincidencia. (uhmm ???)