En informática , una unión es un valor que puede tener cualquiera de varias representaciones o formatos dentro de la misma posición en la memoria ; que consiste en una variable que puede contener dicha estructura de datos . Algunos lenguajes de programación admiten tipos de datos especiales , llamados tipos de unión , para describir dichos valores y variables. En otras palabras, una definición de tipo de unión especificará cuál de un número de tipos primitivos permitidos puede almacenarse en sus instancias, por ejemplo, "float o entero largo". En contraste con un registro (o estructura), que podría definirse para contener un flotante yun número entero; en una unión, solo hay un valor en un momento dado.
Una unión se puede representar como una porción de memoria que se usa para almacenar variables de diferentes tipos de datos. Una vez que se asigna un nuevo valor a un campo, los datos existentes se sobrescriben con los nuevos datos. El área de memoria que almacena el valor no tiene ningún tipo intrínseco (que no sean solo bytes o palabras de memoria), pero el valor puede tratarse como uno de varios tipos de datos abstractos , teniendo el tipo del valor que se escribió por última vez en el área de memoria.
En la teoría de tipos , una unión tiene un tipo de suma ; esto corresponde a la unión disjunta en matemáticas.
Dependiendo del idioma y el tipo, un valor de unión se puede usar en algunas operaciones, como la asignación y la comparación para la igualdad, sin conocer su tipo específico. Otras operaciones pueden requerir ese conocimiento, ya sea por alguna información externa o por el uso de una unión etiquetada .
Uniones no etiquetadas
Debido a las limitaciones de su uso, las uniones sin etiquetar generalmente solo se proporcionan en idiomas sin mecanografiar o de forma no segura con el tipo (como en C ). Tienen la ventaja sobre las uniones etiquetadas simples de no requerir espacio para almacenar una etiqueta de tipo de datos.
El nombre "unión" proviene de la definición formal del tipo. Si un tipo se considera como el conjunto de todos los valores que ese tipo puede asumir, un tipo de unión es simplemente la unión matemática de sus tipos constitutivos, ya que puede tomar cualquier valor que cualquiera de sus campos pueda tomar. Además, debido a que una unión matemática descarta los duplicados, si más de un campo de la unión puede tomar un solo valor común, es imposible saber a partir del valor solo qué campo se escribió por última vez.
Sin embargo, una función de programación útil de las uniones es mapear elementos de datos más pequeños con otros más grandes para facilitar la manipulación. Una estructura de datos que consta, por ejemplo, de 4 bytes y un número entero de 32 bits, puede formar una unión con un número entero de 64 bits sin signo y, por lo tanto, se puede acceder a ella más fácilmente para fines de comparación, etc.
Uniones en varios lenguajes de programación
ALGOL 68
ALGOL 68 ha etiquetado uniones y utiliza una cláusula de caso para distinguir y extraer el tipo de constituyente en tiempo de ejecución. Una unión que contiene otra unión se trata como el conjunto de todas sus posibilidades constituyentes.
La sintaxis del tipo de unión C / C ++ y la noción de conversiones se derivó de ALGOL 68, aunque en una forma sin etiquetar. [1]
C / C ++
En C y C ++ , las uniones sin etiquetar se expresan casi exactamente como estructuras ( estructuras ), excepto que cada miembro de datos comienza en la misma ubicación en la memoria. Los miembros de datos, como en las estructuras, no necesitan ser valores primitivos y, de hecho, pueden ser estructuras o incluso otras uniones. C ++ (desde C ++ 11 ) también permite que un miembro de datos sea de cualquier tipo que tenga un constructor / destructor completo y / o un constructor de copia, o un operador de asignación de copia no trivial. Por ejemplo, es posible tener la cadena C ++ estándar como miembro de una unión.
Como una estructura, todos los miembros de un sindicato son públicos por defecto. Las palabras clave private
, public
y protected
pueden usarse dentro de una estructura o unión exactamente de la misma manera que se usan dentro de una clase para definir el acceso de miembros privado, público y protegido.
El uso principal de una unión es permitir el acceso a una ubicación común mediante diferentes tipos de datos, por ejemplo, acceso de entrada / salida de hardware, uso compartido de campos de bits y palabras, o juegos de palabras . Las uniones también pueden proporcionar polimorfismo de bajo nivel . Sin embargo, no hay verificación de tipos, por lo que depende del programador asegurarse de que se acceda a los campos adecuados en diferentes contextos. El campo relevante de una variable de unión generalmente está determinado por el estado de otras variables, posiblemente en una estructura adjunta.
Un lenguaje común de programación en C usa uniones para realizar lo que C ++ llama reinterpret_cast , asignando a un campo de una unión y leyendo de otro, como se hace en el código que depende de la representación en bruto de los valores. Un ejemplo práctico es el método de calcular raíces cuadradas utilizando la representación IEEE . Sin embargo, este no es un uso seguro de los sindicatos en general.
Los especificadores de estructura y unión tienen la misma forma. [. . . ] El tamaño de un sindicato es suficiente para contener al mayor de sus miembros. El valor de como máximo uno de los miembros se puede almacenar en un objeto de unión en cualquier momento. Un puntero a un objeto de unión, convenientemente convertido, apunta a cada uno de sus miembros (o si un miembro es un campo de bits, entonces a la unidad en la que reside), y viceversa.
- ANSI / ISO 9899: 1990 (el estándar ANSI C) Sección 6.5.2.1
Unión anónima
En C ++, C11 y como una extensión no estándar en muchos compiladores, las uniones también pueden ser anónimas. No es necesario hacer referencia a sus miembros de datos, sino que se accede a ellos directamente. Tienen algunas restricciones a diferencia de las uniones tradicionales: en C11, deben ser miembros de otra estructura o unión, [2] y en C ++, no pueden tener métodos o especificadores de acceso.
Simplemente omitir la parte del nombre de clase de la sintaxis no convierte a una unión en una unión anónima. Para que una unión califique como unión anónima, la declaración no debe declarar un objeto. Ejemplo:
#include #include int main () { union { float f ; std :: uint32_t d ; // Asume que flotante tiene 32 bits de ancho }; f = 3,14f ; std :: cout << "Representación hexadecimal de 3.14f:" << std :: hex << d << '\ n ' ; }
Unión transparente
En compiladores similares a Unix, como GCC, Clang e IBM XL C para AIX, hay un transparent_union
atributo disponible para los tipos de unión. Los tipos contenidos en la unión se pueden convertir de forma transparente al tipo de unión en sí en una llamada de función, siempre que todos los tipos tengan el mismo tamaño. Está diseñado principalmente para funcionar con múltiples interfaces de parámetros, un uso necesario para las primeras extensiones de Unix y la posterior reestandarización. [3]
COBOL
En COBOL , los elementos de datos de unión se definen de dos formas. El primero usa la palabra clave RENAMES (nivel 66), que mapea efectivamente un segundo elemento de datos alfanuméricos en la parte superior de la misma ubicación de memoria que un elemento de datos anterior. En el código de ejemplo siguiente, el elemento de datos PERSON-REC se define como un grupo que contiene otro grupo y un elemento de datos numérico. PERSON-DATA se define como un elemento de datos alfanuméricos que cambia el nombre de PERSON-REC , tratando los bytes de datos que continúan dentro de él como datos de caracteres.
01 PERSONA-REC . 05 NOMBRE DE LA PERSONA . 10 PERSONA-NOMBRE-APELLIDO FOTO X (12) . 10 PERSONA-NOMBRE-PRIMERA FOTO X (16) . 10 nombre-persona-MID PIC X . 05 PERSON-ID PIC 9 (9) PACKED-DECIMAL . 01 PERSON-DATA RENOMBRES PERSON-REC .
La segunda forma de definir un tipo de unión es utilizando la palabra clave REDEFINES . En el código de ejemplo siguiente, el elemento de datos VERS-NUM se define como un entero binario de 2 bytes que contiene un número de versión. Un segundo elemento de datos VERS-BYTES se define como una variable alfanumérica de dos caracteres. Dado que el segundo elemento se redefine sobre el primer elemento, los dos elementos comparten la misma dirección en la memoria y, por lo tanto, comparten los mismos bytes de datos subyacentes. El primer elemento interpreta los dos bytes de datos como un valor binario, mientras que el segundo elemento interpreta los bytes como valores de caracteres.
01 VERS-INFO . 05 VERS-NUM PIC S9 (4) COMP . 05 VERS-BYTES PIC X (2) REDEFINE VERS-NUM
Pascal
En Pascal , hay dos formas de crear sindicatos. Una es la forma estándar a través de un registro variante. El segundo es un medio no estándar de declarar una variable como absoluta, lo que significa que se coloca en la misma ubicación de memoria que otra variable o en una dirección absoluta. Si bien todos los compiladores de Pascal admiten registros variantes, solo algunos admiten variables absolutas.
Para los propósitos de este ejemplo, los siguientes son todos los tipos de números enteros: un byte es de 8 bits, una palabra es de 16 bits y un número entero es de 32 bits.
El siguiente ejemplo muestra la forma absoluta no estándar:
VAR A : Entero ; B : Matriz [ 1 .. 4 ] de Byte absoluto A ; C : entero absoluto 0 ;
En el primer ejemplo, cada uno de los elementos de la matriz B se asigna a uno de los bytes específicos de la variable A. En el segundo ejemplo, la variable C se asigna a la dirección exacta de la máquina 0.
En el siguiente ejemplo, un registro tiene variantes, algunas de las cuales comparten la misma ubicación que otras:
TYPE TSystemTime = año de registro , mes , día de la semana , día : palabra ; Hora , minuto , segundo , milisegundo : palabra ; terminar ; TGender = ( Masculino , Femenino , TransFemale , TransMale , Otro ) ; TPerson = REGISTRO Nombre , Apellido : Cadena ; Fecha de nacimiento : TSystemTime ; Dependientes : Entero ; HourlyRate : Moneda ; Género del caso : TGender of Female , TransMale : ( isPregnant : Boolean ; DateDue : TSystemTime ) ; Masculino , TransFemale : ( HasPartner , isPartnerExpecting : Boolean ; PartnerDate : TSystemTime ) ; FIN ;
En el ejemplo anterior, un registro de Tperson tiene el campo de etiqueta Género , y la etiqueta divide a las personas en dos clases: mujer o hombre trans (una persona con una identidad de género masculina, pero que nació con un cuerpo femenino) y hombre o mujer trans. (una persona con una identidad de género femenina, pero nacida en un cuerpo masculino). En este registro, hasPartner y isPregnant ocupan la misma ubicación, mientras que DateDue y isPartnerExpecting comparte la misma ubicación. Mientras que el registro tiene un campo de etiqueta Sexo , el compilador no impone el acceso de acuerdo con el valor de la etiqueta: se puede acceder a cualquiera de los campos variantes sin importar el valor de la etiqueta, por ejemplo, si el género otro es el valor del campo de etiqueta Sexo , aún se puede acceder a cualquiera de los campos variantes.
PL / I
En PL / I , el término original para una unión era celda , [4] que todavía es aceptado como sinónimo de unión por varios compiladores. La declaración de unión es similar a la definición de estructura, donde los elementos del mismo nivel dentro de la declaración de unión ocupan el mismo almacenamiento. Los elementos de la unión pueden ser de cualquier tipo de datos, incluidas estructuras y matrices. [5] : pp192–193 Aquí vers_num y vers_bytes ocupan las mismas ubicaciones de almacenamiento.
1 unión vers_info , 5 vers_num binario fijo , 5 vers_bytes pic '(2) A';
Una alternativa a una declaración de unión es el atributo DEFINED, que permite declaraciones de almacenamiento alternativas, sin embargo, los tipos de datos de la base y las variables definidas deben coincidir. [5] : págs . 289 a 293
Sintaxis y ejemplo
C / C ++
En C y C ++, la sintaxis es:
union < nombre > { < tipo de datos > < 1 er nombre de variable > ; < tipo de datos > < 2 nd nombre de variable > ; . . . < tipo de datos > < enésimo nombre de variable > ; } < nombre de la variable de unión > ;
Una estructura también puede ser miembro de un sindicato, como muestra el siguiente ejemplo:
union name1 { struct name2 { int a ; flotar b ; char c ; } svar ; int d ; } uvar ;
Este ejemplo define una variable uvar
como una unión (etiquetada como name1
), que contiene dos miembros, una estructura (etiquetada como name2
) nombrada svar
(que a su vez contiene tres miembros) y una variable entera nombrada d
.
Las uniones pueden ocurrir dentro de estructuras y arreglos, y viceversa:
struct { int flags ; char * nombre ; int utype ; union { int ival ; flotar fval ; char * sval ; } u ; } symtab [ NSYM ];
El número ival se denomina symtab[i].u.ival
y el primer carácter de la cadena sval mediante *symtab[i].u.sval
o symtab[i].u.sval[0]
.
PHP
Los tipos de unión se introdujeron en PHP 8.0. [6]
Clase Ejemplo { privado int | float $ foo ; función pública squareAndAdd ( float | int $ bar ) : int | float { return $ bar ** 2 + $ this -> foo ; } }
Mecanografiado
Los tipos de unión son compatibles con TypeScript. [7]
sucesor de la función ( n : número | bigint ) : número | bigint { return ++ n }
Diferencia entre unión y estructura
Una unión es una clase cuyos miembros de datos se asignan a la misma dirección dentro de su objeto. El tamaño de un objeto de una unión es, por lo tanto, el tamaño de su miembro de datos más grande.
En una estructura, todos sus miembros de datos se almacenan en ubicaciones de memoria contiguas. El tamaño de un objeto de una estructura es, por lo tanto, el tamaño de la suma de todos sus miembros de datos.
Esta ganancia en la eficiencia del espacio, aunque valiosa en ciertas circunstancias, tiene un gran costo de seguridad: la lógica del programa debe garantizar que solo lea el campo escrito más recientemente a lo largo de todas las rutas de ejecución posibles. La excepción es cuando se utilizan uniones para la conversión de tipos : en este caso, se escribe un determinado campo y el campo de lectura posterior es deliberadamente diferente.
Como ejemplo que ilustra este punto, la declaración
struct foo { int a ; flotar b ; }
define un objeto de datos con dos miembros que ocupan ubicaciones de memoria consecutivas:
┌─────┬─────┐ foo │ a │ b │ └─────┴─────┘ ↑ ↑Dirección de memoria: 0150 0154
Por el contrario, la declaración
barra sindical { int a ; flotar b ; }
define un objeto de datos con dos miembros que ocupan la misma ubicación de memoria:
┌─────┐ barra │ a │ │ b │ └─────┘ ↑Dirección de memoria: 0150
Las estructuras se utilizan cuando un "objeto" se compone de otros objetos, como un objeto puntual que consta de dos números enteros, que son las coordenadas xey:
typedef struct { int x ; // xey están separados int y ; } tPoint ;
Las uniones se utilizan normalmente en situaciones en las que un objeto puede ser una de muchas cosas, pero solo una a la vez, como un sistema de almacenamiento sin tipos:
typedef enum { STR , INT } tType ; typedef struct { tType typ ; // Typ está separado. union { int ival ; // ival y sval ocupan la misma memoria. char * sval ; }; } tVal ;
Ver también
Referencias
- ^ Ritchie, Dennis M. (marzo de 1993). "El desarrollo del lenguaje C" . Avisos ACM SIGPLAN . 28 (3): 201-208. doi : 10.1145 / 155360.155580 .
El esquema de composición tipográfica adoptado por C tiene una deuda considerable con Algol 68, aunque quizás no surgió en una forma que los partidarios de Algol aprobarían. La noción central que capturé de Algol fue una estructura de tipos basada en tipos atómicos (incluidas las estructuras), compuesta en matrices, punteros (referencias) y funciones (procedimientos). El concepto de uniones y elencos de Algol 68 también tuvo una influencia que apareció más tarde.
- ^ "6.63 Estructura sin nombre y campos de unión" . Consultado el 29 de diciembre de 2016 .
- ^ "Atributos de tipo común: transparent_union" . Usando la colección de compiladores GNU (GCC) .
- ^ IBM Corporation (marzo de 1968). Especificaciones del lenguaje IBM System / 360 PL / I (PDF) . pag. 52 . Consultado el 22 de enero de 2018 .
- ^ a b IBM Corporation (diciembre de 2017). Enterprise PL / I para z / OS PL / I para AIX IBM Developer para z Systems PL / I para Windows Referencia del lenguaje (PDF) . Consultado el 22 de enero de 2018 .
- ^ Karunaratne, Ayesh. "PHP 8.0: Tipos de unión" . PHP.Watch . Consultado el 30 de noviembre de 2020 .
- ^ "Manual - Uniones y tipos de intersección" . www.typescriptlang.org . Consultado el 30 de noviembre de 2020 .
- Kernighan, Brian W .; Ritchie, Dennis M. (1978). El lenguaje de programación C (1ª ed.). Prentice Hall. pag. 138 . ISBN 978-0131101630. Consultado el 23 de enero de 2018 .
enlaces externos
- boost :: variant , una alternativa de tipo seguro a las uniones de C ++
- MSDN: Classes, Structures & Unions , para ejemplos y sintaxis
- diferencias , diferencias entre unión y estructura
- Diferencia entre estructura y unión en C ++