Uniones
Una unión es un tipo definido por el usuario que se compone de campos situados en la misma zona de memoria, debido a lo cual se solapan entre sí. Esto permite escribir un valor de un tipo en una unión, y luego leer su representación interna (a nivel de bits) en la interpretación para otro tipo. Por consiguiente, es posible realizar conversiones no estándar de un tipo a otro.
Los campos de unión pueden ser de cualquier tipo integrado, excepto cadenas, arrays dinámicos y punteros. Además, en las uniones se pueden utilizar estructuras con los mismos tipos de campos simples y sin constructores o destructores.
El compilador asigna para la unión una celda de memoria con un tamaño igual al tamaño máximo entre los tipos de todos los elementos. Así, para la unión con campos como long (8 bytes) y int (4 bytes), se asignarán 8 bytes.
Todos los campos de la unión se encuentran en la misma dirección de memoria, es decir, están alineados al principio de la unión (tienen un desplazamiento de 0, lo que puede comprobarse utilizando offsetof; véase la sección Empaquetar estructuras).
La sintaxis para describir una unión es similar a la estructura pero utiliza la palabra clave union, seguida de un identificador y, a continuación, de un bloque de código con una lista de campos.
Por ejemplo, un algoritmo podría utilizar una matriz del tipo double para almacenar varios ajustes, simplemente porque el tipo double es uno de los que tienen un tamaño máximo en bytes igual a 8. Digamos que entre los ajustes hay números como ulong. Dado que no está garantizado que el tipo double reproduzca con precisión valores de ulong grandes, es necesario utilizar una unión para «empaquetar» ulong en double y «desempaquetarlo» de nuevo.
#define MAX_LONG_IN_DOUBLE 9007199254740992
|
El tamaño de la estructura ulong2double es igual a 8, ya que sus dos campos tienen este tamaño. Así, los campos U y D se solapan completamente.
En el ámbito de los números enteros, 9007199254740992 es el mayor valor que está garantizado con un almacenamiento robusto en double. En este ejemplo, intentamos almacenar un número más en double.
La conversión estándar de ulong en double tiene como resultado una pérdida de precisión: después de escribir 9007199254740993 en una variable d de tipo double leemos de su valor ya «redondeado» 9007199254740992 (para obtener información adicional sobre las sutilezas de almacenar números en el tipo double, véase la sección Números reales).
Al utilizar el conversor, el número 9007199254740993 se escribe en la unión «tal cual», sin conversiones, ya que lo estamos asignando a un campo U de tipo ulong. Su representación en términos de double está disponible, de nuevo sin conversiones, desde el campo D. Podemos copiarlo a otras variables y arrays como double sin preocuparnos.
Aunque el valor resultante double tiene un aspecto extraño, coincide exactamente con el entero original si es necesario extraerlo mediante conversión inversa: escribir en un campo D del tipo double, después leer desde un campo U del tipo ulong.
Una unión puede tener constructores y destructores, así como métodos. Por defecto, los miembros de la unión tienen derechos de acceso público, pero esto puede ajustarse utilizando modificadores de acceso, como en la estructura.