Las uniones son un tipo especial de estructuras que permiten almacenar elementos de diferentes tipos en las mismas posiciones de memoria, aunque evidentemente no simultáneamente.
Sintaxis:
union [<tipo unión>] { [<tipo> <nombre de variable>[, <nombre variable>, ...]] ; } [<variable de unión>[,<variable union>...]] ;
El nombre de la unión es un nombre opcional para referirse a la unión.
Las variables de unión son variables declaradas del tipo de la unión, y su inclusión también es opcional.
Sin embargo, al menos uno de estos elementos debe existir, aunque ambos sean opcionales.
En el interior de una unión, entre las llaves, se pueden definir todos los elementos necesarios, del mismo modo que se declaran las variables. La particularidad es que cada elemento comenzará en la misma posición de memoria.
Las uniones pueden referenciarse completas, usando su nombre, como hacíamos con las estructuras, y también se puede acceder a los elementos en el interior de la unión usando el operador de selección (.), un punto.
También pueden declararse más variables del tipo de la unión en cualquier parte del programa, de la siguiente forma:
[union] <nombre_de_unión> <variable>[,<variable>...];
La palabra "union" es opcional en la declaración de variables en C++. En C es obligatoria.
Ejemplo:
#include <iostream> using namespace std; union unEjemplo { int A; char B; double C; } UnionEjemplo; int main() { UnionEjemplo.A = 100; cout << UnionEjemplo.A << endl; UnionEjemplo.B = 'a'; cout << UnionEjemplo.B << endl; UnionEjemplo.C = 10.32; cout << UnionEjemplo.C << endl; cout << &UnionEjemplo.A << endl; cout << (void*)&UnionEjemplo.B << endl; cout << &UnionEjemplo.C << endl; cout << sizeof(unEjemplo) << endl; cout << sizeof(UnionEjemplo.A) << endl; cout << sizeof(UnionEjemplo.B) << endl; cout << sizeof(UnionEjemplo.C) << endl; cin.get(); return 0; }
Suponiendo que int ocupa dos bytes, char un byte y double 4 bytes, la forma en que se almacena la información en la unión del ejemplo es la siguiente:
[BYTE1][BYTE2][BYTE3][BYTE4] [<----A----->] [<-B->] [<-----------C------------>]
Por el contrario, las mismas variables en una estructura tendrían la siguiente disposición:
[BYTE1][BYTE2][BYTE3][BYTE4][BYTE5][BYTE6][BYTE7] [<----A----->][<-B->][<-----------C------------>]
Nota: Unas notas sobre el ejemplo:
• Observa que
hemos hecho un "casting" del puntero al elemento B de la unión. Si no lo
hiciéramos así, cout encontraría un puntero a char, que se considera como una
cadena, y por defecto intentaría imprimir la cadena, pero nosotros queremos
imprimir el puntero, así que lo convertimos a un puntero de otro tipo.
• Para
averiguar el tamaño de cada campo usando "sizeof" tenemos que usar el operador
de ámbito (::), y no el punto.
• Observa que el tamaño de la unión es el del
elemento más grande.
Otro ejemplo, éste más práctico. Algunas veces tenemos estructuras que son elementos del mismo tipo, por ejemplo X, Y, y Z todos enteros. Pero en determinadas circunstancias, puede convenirnos acceder a ellos como si fueran un array: Coor[0], Coor[1] y Coor[2]. En este caso, la unión puede ser útil:
struct stCoor3D { int X, Y, Z; }; union unCoor3D { struct stCoor3D N; int Coor[3]; } Punto;
Podemos referirnos a la coordenada Y de estas dos formas:
Punto.N.Y Punto.Coor[1]
Como ya vimos en el capítulo sobre estructuras, una estructura anónima es la que carece de identificador de tipo de estructura y de identificador de variables del tipo de estructura.
Por ejemplo, la misma unión del último ejemplo puede declararse de este otro modo:
union unCoor3D { struct { int X, Y, Z; }; int Coor[3]; } Punto;
Haciéndolo así accedemos a la coordenada Y de cualquiera de estas dos formas:
Punto.Y Punto.Coor[1]
Usar estructuras anónimas dentro de una unión tiene la ventaja de que nos ahorramos escribir el identificador de la estructura para acceder a sus campos. Esto no sólo es útil por el ahorro de código, sino sobre todo, porque el código es mucho más claro.
union.
© Septiembre de 2000 Salvador Pozo, salvador@conclase.net