c++ - español - ¿Por qué este reinterpret_cast no compila?
reinterpret_cast c++ ejemplos (9)
Entiendo que reinterpret_cast
es peligroso, solo hago esto para probarlo. Tengo el siguiente código:
int x = 0;
double y = reinterpret_cast<double>(x);
Cuando intento compilar el programa, me da un error diciendo
Conversión no válida del tipo ''float'' al tipo ''double
¿Que esta pasando? Pensé que reinterpret_cast
era el elenco rogue que podías usar para convertir manzanas en submarinos, ¿por qué este simple yeso no se compila?
Al asignar y al valor devuelto por la conversión, realmente no está emitiendo el valor x
, sino que lo está convirtiendo. Es decir, y
no apunta a x
y pretende que apunta a un flotador. La conversión construye un nuevo valor de tipo float
y le asigna el valor de x
. Hay varias formas de hacer esta conversión en C ++, entre ellas:
int main()
{
int x = 42;
float f = static_cast<float>(x);
float f2 = (float)x;
float f3 = float(x);
float f4 = x;
return 0;
}
La única diferencia real es que la última (una conversión implícita) generará un diagnóstico del compilador en niveles de advertencia más altos. Pero todos hacen funcionalmente lo mismo, y en muchos casos lo mismo que en el mismo código de máquina.
Ahora, si realmente quieres pretender que x
es un flotador, entonces realmente quieres lanzar x
, haciendo esto:
#include <iostream>
using namespace std;
int main()
{
int x = 42;
float* pf = reinterpret_cast<float*>(&x);
(*pf)++;
cout << *pf;
return 0;
}
Puedes ver lo peligroso que es esto. De hecho, la salida cuando ejecuto esto en mi máquina es 1
, que decididamente no es 42 + 1.
El compilador rechaza lo que escribiste como una tontería porque int
y double
pueden ser objetos con diferentes tamaños. Podrías lograr el mismo efecto de esta manera, aunque es ciertamente peligroso:
int x = 0;
double y = *reinterpret_cast<double*>(&x);
Esto es potencialmente peligroso porque si y
son diferentes tamaños (digamos que int
es de cuatro bytes y el double
es de ocho bytes), entonces, cuando elimine la referencia de los ocho bytes de memoria en &x
para completar y
accederá a cuatro bytes de x
y cuatro bytes. de ... lo que venga a continuación en la memoria (posiblemente el inicio de y
, o la basura, o algo completamente distinto).
Si desea convertir un entero en un doble, use un static_cast
y realizará la conversión.
Si desea acceder al patrón de bits de x
, conviértalo a algún tipo de puntero conveniente (por ejemplo, byte*
) y acceda hasta sizeof(int) / sizeof(byte)
:
byte* p = reinterpret_cast<byte*>(&x);
for (size_t i = 0; i < sizeof(int); i++) {
// do something with p[i]
}
En C ++, reinterpret_cast
solo puede realizar un conjunto específico de conversiones, enumeradas explícitamente en la especificación del lenguaje. En resumen, reinterpret_cast
solo puede realizar conversiones de puntero a puntero y conversiones de referencia a referencia (más conversiones de puntero a entero y de entero a puntero). Esto es coherente con la intención expresada en el mismo nombre del modelo: está destinado a ser utilizado para la reinterpretación de punteros / referencias.
Lo que estás tratando de hacer no es reinterpretarlo. Si desea reinterpretar un int
como un double
, tendría que convertirlo en un tipo de referencia
double y = reinterpret_cast<double&>(x);
Aunque la reinterpretación equivalente basada en punteros es probablemente más explícita
double y = *reinterpret_cast<double*>(&x); // same as above
Sin embargo, tenga en cuenta que, si bien reinterpret_cast
puede convertir los tipos de referencia / puntero, el intento real de leer los datos a través de la referencia / puntero resultante produce un comportamiento indefinido.
Y, en cualquier caso, esto, por supuesto, no tiene mucho sentido en una plataforma con int
y double
de diferente tamaño (ya que en el caso de un double
mayor, leerá más allá de la memoria ocupada por x
).
Entonces, al final, todo se reduce a lo que intentabas lograr. ¿Reinterpretación de la memoria? Véase más arriba. ¿Algún tipo de int
más significativo para double
conversión? Si es así, reinterpret_cast
no te ayudará aquí.
Eso es interesante. Tal vez esté haciendo una conversión implícita de int a float antes de intentar duplicar la conversión. Los tipos int y float tienden a ser del mismo tamaño en bytes (dependiendo de su sistema, por supuesto).
Lanzar un int a un doble no requiere un lanzamiento. El compilador realizará la asignación de forma implícita.
Reinterpret_cast se utiliza con punteros y referencias, por ejemplo, convertir un int *
en un double *
.
Reinterpretar cast le permite reinterpretar un bloque de memoria como un tipo diferente. Esto tiene que ser realizado en punteros o referencias :
int x = 1;
float & f = reinterpret_cast<float&>(x);
assert( static_cast<float>(x) != f ); // !!
La otra cosa es que, de hecho, es un reparto bastante peligroso, no solo debido a valores extraños que salen como resultado, o la afirmación anterior no falla, sino porque si los tipos son de diferentes tamaños, y se reinterpreta desde ''fuente'' a Tipos de ''destino'', cualquier operación en la referencia / puntero reinterpretada accederá a bytes de sizeof(destination)
. Si sizeof(destination)>sizeof(source)
entonces eso irá más allá de la memoria de la variable real, matando potencialmente su aplicación o sobrescribiendo otras variables distintas del origen o destino:
struct test {
int x;
int y;
};
test t = { 10, 20 };
double & d = reinterpret_cast<double&>( t.x );
d = 1.0/3.0;
assert( t.x != 10 ); // most probably at least.
asswet( t.y != 20 );
Si está intentando convertir los bits de su int
en la representación de un double
, debe convertir la dirección, no el valor. También debe asegurarse de que los tamaños coinciden:
uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);
reinterpret_cast no es un reparto general. Según la sección 5.2.10.1 de la especificación C ++ 03:
Las conversiones que pueden realizarse explícitamente utilizando reinterpret_cast se enumeran a continuación. Ninguna otra conversión se puede realizar explícitamente usando reinterpret_cast.
Y no hay nada en la lista que describa la conversión entre tipos integrales y de punto flotante (o entre tipos integrales, incluso esto es ilegal reinterpret_cast<long>(int(3));
)
reinterpret_cast
se utiliza mejor para los punteros. Por lo tanto, un puntero a un objeto se puede convertir en un "submarino".
Desde msdn :
El operador reinterpret_cast se puede usar para conversiones como char * to int * o One_class * Unrelated_class *, que son inherentemente inseguras.
El resultado de un reinterpret_cast no se puede usar de forma segura para otra cosa que no sea volver a su tipo original. Otros usos son, en el mejor de los casos, no portables.