2010-02-05 10 views
46

Entiendo que reinterpret_cast es peligroso, solo estoy haciendo esto para probarlo. Tengo el siguiente código:¿Por qué no reinterpreta esta compilación?

int x = 0; 
double y = reinterpret_cast<double>(x); 

Cuando intento compilar el programa, me da un error que dice

invalid cast from type 'float' to type 'double 

¿Qué está pasando? Pensé que reinterpret_cast era el elenco canalla que podías usar para convertir manzanas en submarinos, ¿por qué no compilará este sencillo elenco?

+0

No he intentado esto en C++, así que solo estoy adivinando. ¿Funciona si lanzas para flotar? ¿No le gustaría que los dos tipos tengan una longitud de bit diferente? –

+0

"' reinterpret_cast (x) '" ¿Qué esperaba que hiciera esta expresión? – curiousguy

+2

int es 32 bits. el doble es 64 bits. Ese podría ser el problema. ¿Puedes revisar? –

Respuesta

34

Mediante la asignación y al valor devuelto por el elenco no está realmente emitiendo el valor x, 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 maneras de hacer esta conversión en C++, entre ellos:

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 la última (una conversión implícita) generará un compilador de diagnóstico en los niveles más altos de advertencia. Pero todos hacen funcionalmente lo mismo, y en muchos casos realmente lo mismo, como en el mismo código de máquina.

Ahora bien, si usted realmente quiere pretender que x es un flotador, entonces realmente quieres lanzar x, al hacer esto:

#include <iostream> 
using namespace std; 

int main() 
{ 
    int x = 42; 
    float* pf = reinterpret_cast<float*>(&x); 
    (*pf)++; 
    cout << *pf; 
    return 0; 
} 

se puede ver lo peligroso que es. De hecho, la salida cuando ejecuto esto en mi máquina es 1, que decididamente no es 42 + 1.

+0

will (float) x return 42 o alguna representación binaria de un doble no relacionado. Creo que este tipo significa reinterpretar y eso es lo que quiere. –

+0

'(float) x' realizará una conversión, no un molde. –

+0

Su código a continuación es una violación de aliasing estricta y, por lo tanto, tiene un comportamiento indefinido. –

1

reinterpret_cast se utiliza mejor para los punteros. Por lo tanto, un puntero a un objeto se puede convertir en un "submarino".

De msdn:

El operador reinterpret_cast puede utiliza para conversiones tales como char * a int *, o One_class * a Unrelated_class *, que son inherentemente inseguro.

El resultado de una reinterpret_cast no puede usarse de manera segura para cualquier cosa que no sea de ser echado de nuevo a su tipo original. Otros usos son, mejor, no portable.

0

Lanzar un int a doble no requiere conversión. El compilador realizará la asignación implícitamente.

El reinterpret_cast se utiliza con punteros y referencias, por ejemplo, lanzando un int * a un double *.

7

Si usted está tratando de convertir los bits de su int a una representación de un double, es necesario echar la dirección no el valor. También debe asegurarse de que los tamaños coincidan:

uint64_t x = 0x4045000000000000; 
double y = *reinterpret_cast<double *>(&x); 
0

Eso es interesante. Tal vez está haciendo una conversión implícita de int a float antes de intentar duplicar el elenco. Los tipos int y float tienden a tener el mismo tamaño en bytes (dependiendo de su sistema, por supuesto).

3

El compilador rechaza lo que escribió como una tontería porque int y double pueden ser objetos con diferentes tamaños. Se podría conseguir el mismo efecto de esta manera, aunque es ciertamente peligroso:

int x = 0; 
double y = *reinterpret_cast<double*>(&x); 

Esto es potencialmente peligroso ya que si x y y son diversos tamaños (digamos int es de cuatro bytes y double es de ocho bytes) y luego cuando eliminar la referencia de los ocho bytes de memoria en &x rellenar y se accede a cuatro bytes de x y cuatro bytes de ... lo que venga después en la memoria (posiblemente el inicio de y, o basura, o algo completamente distinto.)

Si quieres convertir un entero r a un doble, use un static_cast y llevará a cabo la conversión.

Si desea acceder al patrón de bits de x, fundido a algún tipo de puntero conveniente (por ejemplo, byte*) y el acceso 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] 
} 
+2

No es la razón por la cual el compilador lo rechaza, pero la discusión sobre el tamaño de los tipos es valiosa. –

11

reinterpret_cast no es un modelo general. De acuerdo con la especificación C++ 03, sección 5.2.10.1:

Las conversiones que se pueden realizar de forma explícita con reinterpret_cast se enumeran a continuación. No se puede realizar ninguna otra conversión explícitamente usando reinterpret_cast.

Y no aparece nada que describe la conversión entre tipos de puntos integrales y flotantes (o entre tipos enteros, incluso esto es ilegal reinterpret_cast<long>(int(3));)

2

reinterpretar fundido le permite reinterpretar un bloque de memoria como un tipo diferente . Esto tiene que ser realizada sobre los punteros o referencias:

int x = 1; 
float & f = reinterpret_cast<float&>(x); 
assert(static_cast<float>(x) != f); // !! 

La otra cosa es que es de hecho un reparto bastante peligroso, no sólo debido a los valores extraños que sale como resultado, o la aserción anterior no fallar , sino porque si los tipos son de diferentes tamaños y se reinterpreta de los tipos "fuente" a "destino", cualquier operación en la referencia/puntero reinterpretada accederá a sizeof(destination) bytes. Si sizeof(destination)>sizeof(source) entonces que va a ir más allá de la memoria de variables reales, lo que podría matar a su aplicación o overwritting otras variables distintas de la fuente 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); 
34

En C++ reinterpret_cast sólo puede realizar un conjunto específico de conversiones, que figuran explícitamente en el 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 puntero-a-entero y entero-a-puntero). Esto es coherente con la intención expresada en el nombre del elenco: está destinado a ser utilizado para la reinterpretación de puntero/referencia.

Lo que estás tratando de hacer no es la reinterpretación.Si quiere reinterpretar un int como double que lo tienes que convertirlo a un tipo de referencia

double y = reinterpret_cast<double&>(x); 

aunque la reinterpretación basada en puntero equivalente es probablemente más explícita

double y = *reinterpret_cast<double*>(&x); // same as above 

Nota sin embargo, que mientras que 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 se puede hacer mucho sentido en una plataforma con int y double de diferente tamaño (ya que en caso de mayor double se lee más allá de la memoria ocupada por x).

Por lo tanto, al final todo se reduce a lo que estaba tratando de lograr. Reinterpretación de la memoria? Véase más arriba. ¿Algún tipo de conversión más significativa de int a double? Si es así, reinterpret_cast no lo ayudará aquí.

+0

'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 aplastó la pregunta y podría aceptarse como una respuesta. –

Cuestiones relacionadas