[C con Clase] Uniones

Steven Davidson steven en conclase.net
Mie Mar 7 17:16:26 CET 2007


Hola Alejandro,

El pasado 2007-03-07 14:13:28, Alejandro escribió:

A> Hola, ¿podéis decirme alguna utilidad de las uniones? Es que no encuentro nada para lo que sirva, ya que no puedes guardar más de una cosa a la vez.

Las uniones sirven para guardar un mismo valor o diferentes representaciones en el mismo espacio en memoria. Como ha dicho Ferrán, puedes usar una unión para usar el mismo valor a modo de sobrenombre. Por ejemplo,

union info
{
  short num;
  short cant;
};

Aquí podrías usar indistintamente 'num' como 'cant'. Sinceramente, no usaríamos una unión para esto. Otro ejemplo que sí se usa es:

union byte
{
  struct
  {
    unsigned char b7 : 1;
    unsigned char b6 : 1;
    unsigned char b5 : 1;
    unsigned char b4 : 1;
    unsigned char b3 : 1;
    unsigned char b2 : 1;
    unsigned char b1 : 1;
    unsigned char b0 : 1;
  } bits;
  struct
  {
    unsigned char n1 : 4;
    unsigned char n0 : 4;
  } nibbles;
  unsigned char octeto;
};

Podemos manipular variables de este tipo accediendo tanto a los bits, como a los nibbles (4 bits), directamente con el octeto. Por ejemplo,

byte num1, num2;
...
num2.octeto = 0xA0;
num1.octeto = 0x4F;
num1.nibbles.n1 |= num2.nibbles.n0;

if( num1.bits.b4 )  num2.bits.b7 = num2.bits.b5 & num2.bits.b1;

Es mucho más cómodo trabajar con la información que queremos de esta manera.

Otro ejemplo que también se suele usar es a la hora de representar una matriz en matemáticas. Por ejemplo,

union matriz4x4
{
  struct
  {
    float m11, m12, m13, m14;
    float m21, m22, m23, m24;
    float m31, m32, m33, m34;
    float m41, m42, m43, m44;
  };
  float m[4][4];
};

Seguramente usaremos el array 'm', pero a veces es cómodo usar los nombres de las variables individuales que acceder a los elementos a través del array 'm'. Por ejemplo,

matriz4x4 &identidad( matriz4x4 &ref )
{
  memset( ref.m, 0, sizeof ref.m );
  ref.m11 = ref.m22 = ref.m33 = ref.m44 = 1.0f;
}


Ahora bien, existe otra razón que no tiene que ver con la comodidad sino con diferentes representaciones de datos. Por ejemplo,

struct evento_info
{
  unsigned long nTipo;
  union
  {
    struct raton_info
    {
      int x,y;
      unsigned long estado;
    } ri;

    struct teclado_info
    {
      int tecla;
      unsigned long estado;
    } ti;

    struct red_info
    {
      unsigned long ip[6];
      unsigned char *pDatos;
      unsigned long nCant;
      unsigned long estado;
    } ni;
  };
};

Con esta estructura y unión, podemos guardar diferentes tipos de datos interpretados según el valor del miembro 'nTipo'. Es una forma de agrupar diferentes tipos de datos bajo un mismo tipo. Por ejemplo, digamos que queremos pasar la información a una función. Escribiríamos,

bool func( const evento_info &datos );

Si no tuviéramos esta estructura, entonces necesitaríamos crear varias funciones para cada diferente tipo. Por ejemplo,

struct raton_info {...};
struct teclado_info {...};
struct red_info {...};

bool funcRaton( const raton_info &datos );
bool funcTeclado( const teclado_info &datos );
bool funcRed( const red_info &datos );

Si usas POO, lo anterior no es aconsejable, al menos que la estructura jamás vaya a cambiar y además no necesites aplicar ninguna relación entre las estructuras. Bajo POO, crearíamos una jerarquía de clases, posiblemente usando polimorfismo. Ya llegarás a estos temas más adelante.


Espero haber aclarado las dudas.

Steven


Más información sobre la lista de distribución Cconclase