stringtranslate.com

Tipo de unión

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 varios tipos primitivos permitidos puede almacenarse en sus instancias, por ejemplo, "flotante o entero largo". A diferencia de un registro (o estructura), que podría definirse para contener tanto un flotante como un número entero; en una unión, solo hay un valor en un momento dado.

Una unión puede imaginarse como un trozo de memoria que se utiliza 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 datos nuevos. El área de memoria que almacena el valor no tiene ningún tipo intrínseco (aparte de 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 unión disjunta en matemáticas.

Según el idioma y el tipo, se puede utilizar un valor de unión en algunas operaciones, como asignación y comparación de 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 .

Sindicatos sin etiquetar

Debido a las limitaciones de su uso, las uniones sin etiquetar generalmente solo se proporcionan en lenguajes sin tipo o de forma insegura (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 tomar, un tipo de unión es simplemente la unión matemática de sus tipos que lo constituyen, ya que puede tomar cualquier valor que cualquiera de sus campos pueda tomar. Además, debido a que una unión matemática descarta duplicados, si más de un campo de la unión puede tomar un único 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 asignar elementos de datos más pequeños a otros más grandes para facilitar su manipulación. Una estructura de datos que consta, por ejemplo, de 4 bytes y un entero de 32 bits, puede formar una unión con un entero de 64 bits sin signo y, por lo tanto, se puede acceder más fácilmente a ella con fines de comparación, etc.

Uniones en varios lenguajes de programación.

ALGO 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 a otra unión se trata como el conjunto de todas sus posibilidades constituyentes, y si el contexto lo requiere, una unión es automáticamente forzada a formar parte de la unión más amplia. Una unión no puede contener explícitamente ningún valor, que pueda distinguirse en tiempo de ejecución. Un ejemplo es:

 modo  nodo = unión ( real , int , cadena , vacío );  nodo n := "abc";  caso n en ( r real ): print(("real:", r)), ( int i): imprimir(("int:", i)), ( cadena s): print(("cadena:", s)), ( void ): print(("void:", "EMPTY")), out print(("?:", n)) esac

La sintaxis del tipo de unión C/C++ y la noción de conversiones se derivaron de ALGOL 68, aunque sin etiquetar. [1]

C/C++

En C y C++ , las uniones sin etiquetar se expresan casi exactamente como estructuras ( structs ), 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 estándar de C++ como miembro de una unión.

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 con tipos . 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 suele estar determinado por el estado de otras variables, posiblemente en una estructura adjunta.

Un lenguaje común de programación en C utiliza uniones para realizar lo que C++ llama a reinterpret_cast, asignando a un campo de una unión y leyendo desde otro, como se hace en el código que depende de la representación sin formato 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, adecuadamente 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 (la norma ANSI C) Sección 6.5.2.1

Unión anónima

En C++, C11 y como 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 ni especificadores de acceso.

Simplemente omitir la parte de la sintaxis del nombre de clase 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:

#incluir <iostream> #incluir <cstdint>  int principal () { unión { flotador f ; std :: uint32_t d ; // Asume que el flotador tiene 32 bits de ancho };           f = 3,14f ; std :: cout << "Representación hexadecimal de 3.14f:" << std :: hex << d << '\n' ; }            

Las uniones anónimas también son útiles en structlas definiciones de C para proporcionar una sensación de espacio de nombres. [3]

Unión transparente

En compiladores como GCC, Clang e IBM XL C para AIX, transparent_unionhay un 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á destinado principalmente a funcionar con interfaces de múltiples parámetros, un uso necesario por las primeras extensiones de Unix y la posterior estandarización. [4]

COBOL

En COBOL , los elementos de datos de unión se definen de dos maneras. El primero utiliza la palabra clave RENAMES (nivel 66), que asigna efectivamente un segundo elemento de datos alfanuméricos encima 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éricos. 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-PERSONA . 10 PERSONA-NOMBRE-APELLIDO FOTO X(12) . 10 PERSONA-NOMBRE-PRIMER FOTO X(16) . 10 PERSONA-NOMBRE-MID FOTO X . 05 FOTO DE IDENTIFICACIÓN DE PERSONA 9(9) EMPAQUETADO-DECIMAL .  01 DATOS-PERSONA RENOMBRA PERSON-REC .                

La segunda forma de definir un tipo de unión es mediante 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 primero, 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 FOTO S9(4) COMP . 05 VERS-BYTES PIC X(2) REDEFINE VERS-NUM        

Pascal

En Pascal , hay dos maneras de crear uniones. 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, sólo algunos admiten variables absolutas.

Para los propósitos de este ejemplo, los siguientes son todos tipos de números enteros: un byte consta de 8 bits, una palabra tiene 16 bits y un número entero tiene 32 bits.

El siguiente ejemplo muestra la forma absoluta no estándar:

var A : Entero ; B : matriz [ 1 .. 4 ] del 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:

escriba Forma = ( Círculo , Cuadrado , Triángulo ) ; Dimensiones = caja de registro Figura : Forma del Círculo : ( Diámetro : real ) ; Cuadrado : ( Ancho : real ) ; Triángulo : ( Lado : real ; Ángulo1 , Ángulo2 : 0 .. 360 ) fin ;                          

PL/I

En PL/I, el término original para unión era celda , [5] 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 en el 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. [6] : págs. 192–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 alternativas de almacenamiento; sin embargo, los tipos de datos de las variables base y definidas deben coincidir. [6] : págs. 289-293 

Óxido

Rust implementa uniones etiquetadas y no etiquetadas. En Rust, las uniones etiquetadas se implementan mediante la enumpalabra clave. A diferencia de los tipos enumerados en la mayoría de los demás lenguajes, las variantes de enumeración en Rust pueden contener datos adicionales en forma de tupla o estructura, lo que las convierte en uniones etiquetadas en lugar de simples tipos enumerados. [7]

Rust también admite uniones sin etiquetar utilizando la unionpalabra clave. El diseño de memoria de las uniones en Rust no está definido de forma predeterminada, [8] pero una unión con el #[repr(C)]atributo se distribuirá en la memoria exactamente como la unión equivalente en C. [9] La lectura de los campos de una unión solo se puede realizar dentro de un unsafefunción o bloque, ya que el compilador no puede garantizar que los datos de la unión sean válidos para el tipo de campo; si este no es el caso, se producirá un comportamiento indefinido . [10]

Sintaxis y ejemplo

C/C++

En C y C++, la sintaxis es:

unión <nombre> { < tipo de datos > < primer nombre de variable > ; < tipo de datos > < nombre de la segunda 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:

nombre de unión1 { nombre de estructura2 { int a ; flotar b ; carácter c ; } var ; int d ; } uvar ;                

Este ejemplo define una variable uvarcomo una unión (etiquetada como name1), que contiene dos miembros, una estructura (etiquetada como name2) denominada svar(que a su vez contiene tres miembros) y una variable entera denominada d.

Las uniones pueden ocurrir dentro de estructuras y conjuntos, y viceversa:

estructura { int banderas ; nombre del personaje ; tipo int ; unión { intival ;valor flotante ; char * sval ; } tu ; } pestaña simbólica [ NSYM ];                  

El número ival se denomina symtab[i].u.ivaly el primer carácter de la cadena sval por cualquiera de *symtab[i].u.svalo symtab[i].u.sval[0].

PHP

Los tipos de unión se introdujeron en PHP 8.0. [11] Los valores están implícitamente "etiquetados" con un tipo por el lenguaje y pueden recuperarse mediante "gettype()".

clase  Ejemplo {  privado  int | flotar  $foo ;  función  pública squareAndAdd ( float | int  $bar ) :  int | float  {  return  $bar  **  2  +  $this -> foo ;  } }

Pitón

La compatibilidad con la escritura se introdujo en Python 3.5. [12] La nueva sintaxis para los tipos de unión se introdujo en Python 3.10. [13]

clase  Ejemplo :  foo  =  0 def  square_and_add ( self ,  barra :  int  |  float )  ->  int  |  flotador :  barra de retorno  ** 2 + uno mismo . foo    

Mecanografiado

Los tipos de unión son compatibles con TypeScript. [14] Los valores están implícitamente "etiquetados" con un tipo por el lenguaje y pueden recuperarse mediante una typeofllamada a valores primitivos y una instanceofcomparación para tipos de datos complejos. Los tipos con uso superpuesto (por ejemplo, existe un método de corte tanto en cadenas como en matrices, el operador más funciona tanto en cadenas como en números) no necesitan una limitación adicional para usar estas funciones.

sucesor de función ( n : número | bigint ) : número | bigint { // los tipos que admiten las mismas operaciones no necesitan acotarse return ++ n ; }           la función depende de Parametro ( v : cadena | Array < cadena > | número ) { // los tipos distintos necesitan limitarse if ( v instancia de Array ) { // hacer algo } else if ( typeof ( v ) === "cadena" ) { // hacer algo más } más { // tiene que ser un número } }                           

Óxido

Las uniones etiquetadas en Rust usan la enumpalabra clave y pueden contener variantes de tupla y estructura:

enumeración  Foo { Bar ( i32 ), Baz { x : Cadena , y : i32 }, }     

Las uniones sin etiquetar en Rust usan la unionpalabra clave:

unión  Foo { barra : i32 , baz : bool , } 

La lectura de los campos de una unión sin etiquetar da como resultado un comportamiento indefinido si los datos de la unión no son válidos como tipo de campo y, por lo tanto, requieren un unsafebloque:

let x = Foo { barra : 10 }; let y = inseguro { x . bar }; // Esto establecerá y en 10 y no dará como resultado un comportamiento indefinido. sea ​​z = inseguro { x . baz }; // Esto da como resultado un comportamiento indefinido, ya que el valor almacenado en x no es un bool válido.                    

Ver también

Referencias

  1. ^ 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 tal vez no surgió en una forma que los seguidores de Algol aprobarían. La noción central que capté de Algol fue una estructura de tipos basada en tipos atómicos (incluidas estructuras), compuesta en matrices, punteros (referencias) y funciones (procedimientos). También tuvo una influencia que apareció más tarde el concepto de uniones y moldes de Algol 68.
  2. ^ "6.63 Campos de unión y estructura sin nombre" . Consultado el 29 de diciembre de 2016 .
  3. ^ Siebenmann., Chris. "CUnionsForNamespaces". utcc.utoronto.ca .
  4. ^ "Atributos de tipo común: transparent_union". Usando la colección de compiladores GNU (GCC) .
  5. ^ IBM Corporation (marzo de 1968). Especificaciones del lenguaje IBM System/360 PL/I (PDF) . pag. 52 . Consultado el 22 de enero de 2018 .
  6. ^ ab 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 .
  7. ^ "Cómo implementa Rust los sindicatos etiquetados: Pat Shaughnessy". patshaughnessy.net . Consultado el 25 de abril de 2023 .
  8. ^ "Tipos de sindicatos: la referencia de Rust". doc.rust-lang.org . Consultado el 25 de abril de 2023 .
  9. ^ "Diseño tipográfico: la referencia de Rust". doc.rust-lang.org . Consultado el 25 de abril de 2023 .
  10. ^ "Sindicatos: la referencia de Rust". doc.rust-lang.org . Consultado el 25 de abril de 2023 .
  11. ^ Karunaratne, Ayesh. "PHP 8.0: tipos de unión". PHP.Ver . Consultado el 30 de noviembre de 2020 .
  12. ^ "mecanografía - Compatibilidad con sugerencias de escritura - Documentación de Python 3.9.7". docs.python.org . Consultado el 8 de septiembre de 2021 .
  13. ^ "PEP 604: permitir escribir tipos de unión como X | Y". Python.org . Consultado el 8 de septiembre de 2021 .
  14. ^ "Manual: uniones y tipos de intersecciones". www.typescriptlang.org . Consultado el 30 de noviembre de 2020 .

enlaces externos