En informática , la conversión de tipos , [1] [2] conversión de tipos , [1] [3] coerción de tipos , [3] y malabarismo de tipos [4] [5] son diferentes formas de cambiar una expresión de un tipo de datos a otro. . Un ejemplo sería la conversión de un valor entero en un valor de coma flotante o su representación textual como una cadena , y viceversa. Las conversiones de tipos pueden aprovechar ciertas características de las jerarquías de tipos o representaciones de datos . Dos aspectos importantes de una conversión de tipo son si ocurre implícita (automáticamente) o explícitamente , [1] [6] y si la representación de datos subyacente se convierte de una representación a otra, o si una representación determinada simplemente se reinterpreta como la representación de otra. tipo de datos. [6] [7] En general, se pueden convertir tipos de datos tanto primitivos como compuestos.
Cada lenguaje de programación tiene sus propias reglas sobre cómo se pueden convertir los tipos. Los lenguajes con tipificación fuerte generalmente realizan pocas conversiones implícitas y desalientan la reinterpretación de representaciones, mientras que los lenguajes con tipificación débil realizan muchas conversiones implícitas entre tipos de datos. Un lenguaje de escritura débil a menudo permite obligar al compilador a interpretar arbitrariamente un elemento de datos como si tuviera representaciones diferentes; esto puede ser un error de programación no obvio o un método técnico para tratar directamente con el hardware subyacente.
En la mayoría de los idiomas, la palabra coerción se utiliza para indicar una conversión implícita , ya sea durante la compilación o durante el tiempo de ejecución . Por ejemplo, en una expresión que mezcla números enteros y de punto flotante (como 5 + 0,1), el compilador convertirá automáticamente la representación de números enteros en una representación de punto flotante para que no se pierdan las fracciones. Las conversiones de tipos explícitas se indican escribiendo código adicional (por ejemplo, añadiendo identificadores de tipo o llamando a rutinas integradas ) o codificando rutinas de conversión para que el compilador las utilice cuando, de otro modo, se detendría por una falta de coincidencia de tipos.
En la mayoría de los lenguajes tipo ALGOL , como Pascal , Modula-2 , Ada y Delphi , la conversión y la conversión son conceptos claramente diferentes. En estos lenguajes, la conversión se refiere a cambiar implícita o explícitamente un valor de un formato de almacenamiento de tipo de datos a otro, por ejemplo, un entero de 16 bits a un entero de 32 bits. Las necesidades de almacenamiento pueden cambiar como resultado de la conversión, incluida una posible pérdida de precisión o truncamiento. La palabra conversión , por otro lado, se refiere a cambiar explícitamente la interpretación del patrón de bits que representa un valor de un tipo a otro. Por ejemplo, 32 bits contiguos pueden tratarse como una matriz de 32 valores booleanos, una cadena de 4 bytes, un entero de 32 bits sin signo o un valor de punto flotante de precisión simple IEEE. Debido a que los bits almacenados nunca se modifican, el programador debe conocer detalles de bajo nivel, como el formato de representación, el orden de los bytes y las necesidades de alineación, para realizar una conversión significativa.
En la familia de lenguajes C y ALGOL 68 , la palabra conversión generalmente se refiere a una conversión de tipo explícita (a diferencia de una conversión implícita), lo que genera cierta ambigüedad sobre si se trata de una reinterpretación de un patrón de bits o una representación de datos real. conversión. Más importante es la multitud de formas y reglas que se aplican a qué tipo de datos (o clase) se ubica mediante un puntero y cómo el compilador puede ajustar un puntero en casos como la herencia de objetos (clases).
Ada proporciona una función de biblioteca genérica Unchecked_Conversion. [8]
La conversión de tipos implícita, también conocida como coerción o malabarismo de tipos , es una conversión de tipos automática realizada por el compilador . Algunos lenguajes de programación permiten que los compiladores proporcionen coerción; otros lo requieren.
En una expresión de tipo mixto, los datos de uno o más subtipos se pueden convertir a un supertipo según sea necesario en tiempo de ejecución para que el programa se ejecute correctamente. Por ejemplo, el siguiente es un código legal en lenguaje C :
doble d ; l largo ; int yo ; si ( re > yo ) d = yo ; si ( yo > l ) l = yo ; si ( d == l ) d *= 2 ;
Aunque d , l e i pertenecen a tipos de datos diferentes, se convertirán automáticamente en tipos de datos iguales cada vez que se ejecute una comparación o asignación. Este comportamiento debe utilizarse con precaución, ya que pueden surgir consecuencias no deseadas . Se pueden perder datos al convertir representaciones de punto flotante a enteros, ya que los componentes fraccionarios de los valores de punto flotante se truncarán (redondearán hacia cero). Por el contrario, se puede perder precisión al convertir representaciones de números enteros a puntos flotantes, ya que es posible que un tipo de punto flotante no pueda representar exactamente todos los valores posibles de algún tipo de número entero. Por ejemplo, podría ser un tipo de precisión simple IEEE 754 , que no puede representar el número entero 16777217 exactamente, mientras que un tipo entero de 32 bits sí puede. Esto puede provocar un comportamiento poco intuitivo, como lo demuestra el siguiente código:float
#incluir <stdio.h> int principal ( vacío ) { int i_value = 16777217 ; valor_f flotante = 16777216.0 ; printf ( "El número entero es: %d \n " , i_value ); printf ( "El valor flotante es: %f \n " , f_value ); printf ( "Su igualdad: %d \n " , i_value == f_value ); }
En los compiladores que implementan flotantes como precisión simple IEEE e ints como al menos 32 bits, este código dará esta impresión peculiar:
El número entero es: 16777217El flotador es: 16777216.000000Su igualdad: 1
Tenga en cuenta que 1 representa igualdad en la última línea de arriba. Este comportamiento extraño se debe a una conversión implícita de i_value
a flotante cuando se compara con f_value
. La conversión provoca pérdida de precisión, lo que hace que los valores sean iguales antes de la comparación.
Conclusiones importantes:
float
provoca int
el truncamiento , es decir, la eliminación de la parte fraccionaria.double
provoca float
el redondeo del dígito.long
Esto int
provoca la caída del exceso de bits de orden superior.Un caso especial de conversión de tipos implícita es la promoción de tipos, donde un objeto se convierte automáticamente en otro tipo de datos que representa un superconjunto del tipo original. Las promociones se usan comúnmente con tipos más pequeños que el tipo nativo de la unidad lógica aritmética (ALU) de la plataforma de destino, antes de las operaciones aritméticas y lógicas, para hacer posibles dichas operaciones, o más eficientes si la ALU puede trabajar con más de un tipo. C y C++ realizan dicha promoción para objetos de tipo booleano, carácter, carácter ancho, enumeración y entero corto que se promueven a int, y para objetos de tipo float, que se promueven a double. A diferencia de otros tipos de conversiones, las promociones nunca pierden precisión ni modifican el valor almacenado en el objeto.
En Java :
int x = 3 ; doble y = 3,5 ; Sistema . afuera . imprimirln ( x + y ); // La salida será 6.5
La conversión de tipos explícita, también llamada conversión de tipos, es una conversión de tipos que se define explícitamente dentro de un programa (en lugar de realizarse automáticamente de acuerdo con las reglas del lenguaje para la conversión de tipos implícita). Lo solicita el usuario en el programa.
doble da = 3,3 ; doble db = 3,3 ; doble CC = 3,4 ; resultado int = ( int ) da + ( int ) db + ( int ) dc ; // resultado == 9 // si se utilizara la conversión implícita (como con "resultado = da + db + dc"), el resultado sería igual a 10
Hay varios tipos de conversión explícita.
En los lenguajes de programación orientados a objetos , los objetos también se pueden convertir : una referencia de una clase base se convierte en una de sus clases derivadas.
En C# , la conversión de tipos se puede realizar de forma segura o insegura (es decir, similar a C); la primera se denomina conversión de tipos comprobada . [9]
Animal animal = nuevo Gato (); Bulldog b = ( Bulldog ) animal ; // si (el animal es Bulldog), stat.type(animal) es Bulldog, en caso contrario, una excepción b = animal as Bulldog ; // si (el animal es Bulldog), b = (Bulldog) animal, de lo contrario b = nulo animal = nulo ; b = animal como Bulldog ; // b == nulo
En C++ se puede lograr un efecto similar utilizando la sintaxis de conversión estilo C++ .
Animal * animal = nuevo Gato ; Bulldog * b = static_cast < Bulldog *> ( animal ); // compila solo si Animal o Bulldog se deriva del otro (o del mismo) b = dynamic_cast < Bulldog *> ( animal ); // si (el animal es Bulldog), b = (Bulldog*) animal, de lo contrario b = nullptr Bulldog & br = static_cast < Bulldog &> ( * animal ); // igual que el anterior, pero se generará una excepción si se devuelve un nullptr // esto no se ve en el código donde se evita el manejo de excepciones eliminar animal ; // recursos siempre libres animal = nullptr ; b = Dynamic_cast < Bulldog *> ( animal ); // b == nuloptr
En Eiffel, la noción de conversión de tipos está integrada en las reglas del sistema de tipos. La Regla de Asignación dice que una asignación, como por ejemplo:
x := y
es válido si y sólo si el tipo de su expresión fuente, y
en este caso, es compatible con el tipo de su entidad de destino, x
en este caso. En esta regla, compatible con significa que el tipo de expresión de origen se ajusta o se convierte al de destino. La conformidad de tipos se define mediante las reglas familiares de polimorfismo en la programación orientada a objetos . Por ejemplo, en la tarea anterior, el tipo de y
se ajusta al tipo de x
si la clase en la que y
se basa es descendiente de aquella en la que x
se basa.
Las acciones de conversión de tipo en Eiffel, específicamente convierte a y convierte desde, se definen como:
Un tipo basado en una clase CU se convierte en un tipo T basado en una clase CT (y T se convierte de U) si
- CT tiene un procedimiento de conversión que utiliza U como tipo de conversión, o
- CU tiene una consulta de conversión que incluye T como tipo de conversión
Eiffel es un lenguaje totalmente compatible con Microsoft .NET Framework . Antes del desarrollo de .NET, Eiffel ya contaba con extensas bibliotecas de clases. El uso de bibliotecas de tipos .NET, particularmente con tipos comúnmente utilizados como cadenas, plantea un problema de conversión. El software Eiffel existente usa las clases de cadena (como STRING_8
) de las bibliotecas de Eiffel, pero el software Eiffel escrito para .NET debe usar la clase de cadena .NET ( System.String
) en muchos casos, por ejemplo, cuando llama a métodos .NET que esperan elementos de .NET. tipo que se pasará como argumentos. Por lo tanto, la conversión de estos tipos hacia adelante y hacia atrás debe ser lo más fluida posible.
my_string : STRING_8 -- Cadena Eiffel nativa my_system_string : SYSTEM_STRING -- Cadena .NET nativa ... mi_cadena := mi_cadena_sistema
En el código anterior, se declaran dos cadenas, una de cada tipo diferente ( SYSTEM_STRING
es el alias compatible con Eiffel para System.String). Como System.String
no se ajusta a STRING_8
, la asignación anterior sólo es válida si System.String
se convierte a STRING_8
.
La clase Eiffel STRING_8
tiene un procedimiento de conversión make_from_cil
para objetos de tipo System.String
. Los procedimientos de conversión también siempre se designan como procedimientos de creación (similares a los constructores). El siguiente es un extracto de la STRING_8
clase:
clase STRING_8 ... crear make_from_cil ... convertir make_from_cil ({ SYSTEM_STRING }) ...
La presencia del procedimiento de conversión hace que la asignación:
mi_cadena := mi_cadena_sistema
semánticamente equivalente a:
crear mi_cadena . make_from_cil ( mi_cadena_sistema )
en el cual my_string
se construye como un nuevo objeto de tipo STRING_8
con contenido equivalente al de my_system_string
.
Para manejar una tarea con el origen original y el destino invertidos:
mi_cadena_sistema := mi_cadena
la clase STRING_8
también contiene una consulta de conversión to_cil
que generará un System.String
a partir de una instancia de STRING_8
.
clase STRING_8 ... crear make_from_cil ... convertir make_from_cil ({ SYSTEM_STRING }) en_cil : { SYSTEM_STRING } ...
La asignación:
mi_cadena_sistema := mi_cadena
entonces, se vuelve equivalente a:
mi_cadena_sistema := mi_cadena . to_cil
En Eiffel, la configuración para la conversión de tipos se incluye en el código de clase, pero luego parece ocurrir tan automáticamente como la conversión de tipos explícita en el código del cliente. Incluye no solo asignaciones sino también otros tipos de archivos adjuntos, como la sustitución de argumentos (parámetros).
Rust no proporciona conversión de tipos implícita (coerción) entre tipos primitivos. Sin embargo, la conversión de tipo explícita (casting) se puede realizar utilizando la as
palabra clave. [10]
sea x = 1000 ; imprimir! ( "1000 como u16 es: {}" , x como u16 );
Muchos lenguajes de programación admiten tipos de unión que pueden contener un valor de varios tipos. Las uniones sin etiquetar se proporcionan en algunos lenguajes con verificación de tipo flexible, como C y PL/I , pero también en el Pascal original . Estos se pueden utilizar para interpretar el patrón de bits de un tipo como un valor de otro tipo.
En piratería , el encasillamiento es el uso indebido de la conversión de tipos para cambiar temporalmente el tipo de datos de una variable respecto de cómo se definió originalmente. [11] Esto brinda oportunidades para los piratas informáticos, ya que en la conversión de tipos después de que una variable se "encasilla" para convertirse en un tipo de datos diferente, el compilador tratará esa variable pirateada como el nuevo tipo de datos para esa operación específica. [12]