Conversión entre tipos de datos¶
El hecho de que C++ sea un lenguaje estáticamente tipado, significa que los tipos asignados a las variables se comprueban en tiempo de compilación.
Así, el compilador verifica que las operaciones que el programador ha escrito en el código fuente están soportadas por el lenguaje. Si existe alguna incompatibilidad, el compilador avisará con un mensaje de error.
Como acabamos de ver, difícilmente el compilador podría realizar esta tarea si previamente no hemos declarado los tipos de las variables antes de ser utilizadas.
No obstante, los lenguajes estáticamente tipados sí que permiten mezclar tipos de dato en las expresiones a pesar de que sus representaciones internas sean diferentes.
Para trabajar de forma cómoda con estas situaciones, los lenguajes permiten que el programador adopte dos tipos de decisión:
Conversión implícita: El compilador se encarga de forma automática de adaptar las representaciones para poder efectuar los cálculos de forma correcta.
Conversión explícita: El programador escribe explícitamente en el código fuente cómo quiere que se haga la conversión entre las representaciones.
Conversión implícita¶
Inicialización directa y asignaciones¶
C++ evalúa la expresión a la derecha del operador =
y el resultado se convierte implícitamente al tipo de dato situado a su izquierda.
La conversión de una expresión con un valor de tipo real a una variable de tipo entero se trunca al entero resultante de eliminar la parte fraccionaria.
int r = 48.1; // r se almacenará como entero con valor 48 int s = -28.1; // s se almacenará como entero con valor -28
La conversión de una expresión con un valor de tipo entero a una variable de tipo real se realizará según la norma IEEE 754. Puede conllevar la pérdida de precisión en números grandes para los
float
, no así para losdouble
, que tienen suficientes bits (una razón más para usar siempredouble
).float x = 19999999; // x se almacenara como real 20000000 double y = 19999999; // y se almacenara como real 19999999
Una expresión no boolena solo se asigna a
false
si el valor es0
. En caso contrario, el resultado de la asignación estrue
.bool b = 48.1; // b es cierto bool b{1}; // OK: inicialización uniforme sólo valores 0 (false) y 1 (true) bool b{48.1}; // ERROR: inicialización uniforme
Operaciones en expresiones¶
Cuando aparece una expresión con distintos tipos de datos mezclados, C++ promueve todos los tipos a un único tipo, el que tiene más jerarquía de entre los presentes. De esta forma, la operación (aritmética o lógica) se realiza según la representación del tipo de mayor jerarquía.
Para los tipos de datos que vamos a manejar en la asignatura, la jerarquía de menor a mayor en C++ es:
bool
<int
char
<int
<float
<double
Véase el siguiente ejemplo.
int x = 1;
double y = 19999998;
// x + y es una expresión RValue que se evalúa como double.
// Al ejecutarse el programa, su valor será 19999999.
float w = x + y; // w se almacena con valor float 20000000
double z = x + y; //z se almacena con valor double 19999999
Conversión explícita¶
En ocasiones el programador necesita forzar la conversión.
Imaginemos un problema en el cual deseamos calcular la pendiente media de un puerto de montaña. Para la longitud del puerto y para la altitud se han elegido variables enteras que representan metros.
La fórmula será \(pendiente = altitud/longitud\).
Un programa ejemplo podría ser el siguiente:
#include <iostream>
using namespace std;
int main()
{
int longitud = 18342;
int altitud = 1123; //Respecto a la base del puerto
double pendiente = altitud/longitud;
cout << "La pendiente es " << pendiente << endl;
}
Edita, compila y ejecuta el código
Quizás para muchos sea una sorpresa que el resultado para la pendiente sea 0
, pero
es totalmente lógico.
Las expresiones a la derecha de una asignación =
se evalúan antes de realizarse
la asignación, almacenándose en un registro interno. En el ejemplo,
la operación altitud/longitud
es una expresión que involucra 2 variables tipo int
y puesto que el resultado real es 0.xxxx
se trunca a 0
. Y es este valor 0
el que se asigna a la variable pendiente
.
Un programa para obtener el valor correcto sustituiría la línea de cálculo de la pendiente por la siguiente:
double pendiente = static_cast<double>(altitud)/longitud;
// double pendiente = double(altitud)/longitud; //Estilo C++ antiguo
// double pendiente = (double)altitud/longitud; //Estilo C
Edita, compila y ejecuta el código
La conversión forzada de tipos static_cast<tipo_de_dato>(expresion)
convierte
la representación interna de expresion
a la representación marcada por tipo_de_dato
.
En nuestro ejemplo, forzamos a que la representación interna de la variable altitud
sea
double
. De esta forma, la expresión altitud/longitud
se convertirá implícitamente
a double
y obtendremos el resultado correcto.
Existen otras alternativas para realizar conversiones forzadas tales como:
double pendiente=double(altitud)/longitud;
double pendiente=(double)altitud/longitud;
Aunque para el ejemplo que nos ocupa todas las opciones son válidas y
compilarán perfectamente, se recomienda usar static_cast
.
La conversión forzada:
double pendiente = static_cast<double>(altitud/longitud);
no funciona correctamente. ¿Por qué?
Por otro lado, en la medida de lo posible, debemos evitar el uso de las conversiones forzadas. En el ejemplo hubiese bastado con declarar:
double longitud = 18342;
double altitud = 1123;
Peligro
Las conversiones descontroladas conllevan graves riesgos. Un ejemplo clásico es el ocurrido con el cohete Ariane, que se produjo por una conversión desde un número en coma flotante de 64 bits (que era mayor de 32768) a un número entero de 16 bits.