Domanda

Capisco che reinterpret_cast è pericoloso, sto solo facendo questo per testarlo. Ho il seguente codice:

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

Quando provo a compilare il programma, mi dà un errore che dice

  

Cast valida dal tipo 'float' di tipo 'double

Che cosa sta succedendo? Ho pensato che fosse il cast reinterpret_cast canaglia che si potrebbe usare per convertire le mele ai sottomarini, perché questa semplice cast non compilerà?

È stato utile?

Soluzione

Con l'assegnazione y al valore restituito dal cast non siete realmente lanciare il x valore, si sta convertendo esso. Cioè, y non punta a x e fingere che punti ad un galleggiante. Conversione costruisce un nuovo valore di tipo float e assegna il valore da x. Ci sono diversi modi per fare questa conversione in C ++, tra i quali:

int main()
{
    int x = 42;
    float f = static_cast<float>(x);
    float f2 = (float)x;
    float f3 = float(x);
    float f4 = x;
    return 0;
}

L'unica vera differenza è l'ultimo (una conversione implicita) genererà un compilatore di diagnosi sui livelli di pericolo più elevati. Ma fanno tutti funzionalmente la stessa cosa - e in molti casi effettivamente la stessa cosa, come lo stesso codice macchina

.

Ora, se davvero si vuole far finta che x è un galleggiante, allora davvero si vuole lanciare x, in questo modo:

#include <iostream>
using namespace std;

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

Si può vedere quanto sia pericoloso questo è. Infatti, l'output quando eseguire questo sulla mia macchina è 1, che è decisamente poco 42 + 1.

Altri suggerimenti

In C ++ reinterpret_cast può eseguire solo un insieme specifico di conversioni, esplicitamente elencati nella specifica del linguaggio. In breve, reinterpret_cast può eseguire solo le conversioni puntatore a puntatore e riferimento to riferimento conversioni (più puntatore a intero e conversioni intero-to-puntatore). Ciò è coerente con l'intento espresso nel nome del cast:. Esso è destinato ad essere utilizzato per la reinterpretazione puntatore / riferimento

Quello che si sta cercando di fare non è reinterpretazione. Se si vuole reinterpretare un int come double ci si deve convertirlo in un tipo di riferimento

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

anche se l'equivalente reinterpretazione puntatore-based è probabilmente più esplicito

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

Nota però, che mentre reinterpret_cast può convertire i tipi di riferimento / puntatore, il tentativo effettivo di leggere i dati attraverso il riferimento risultante / puntatore produce un comportamento indefinito.

E in ogni caso questo, naturalmente, non può avere molto senso su una piattaforma con int e double di diverse dimensioni (in quanto in caso di double più grande potrete leggere al di là della memoria occupata da x).

Così, alla fine, tutto si riduce a quello che stavi cercando di raggiungere. Memoria reinterpretazione? Vedi sopra. Una specie di int più significativo per double conversione? Se è così, reinterpret_cast non vi aiuterà qui.

reinterpret_cast non è un cast generale. Secondo la sezione spec C ++ 03 5.2.10.1:

  

Le conversioni che possono essere eseguite in modo esplicito utilizzando reinterpret_cast sono elencati di seguito. Nessun'altra conversione può essere eseguita in modo esplicito utilizzando reinterpret_cast.

E non c'è nulla elencato che descrive la conversione tra tipi di punti integrali e galleggianti (o tra tipi integrali, anche questo è reinterpret_cast<long>(int(3)); illegale)

Se si sta tentando di convertire i bit del vostro int a una rappresentazione di un double, è necessario lanciare il Indirizzo non il valore. È inoltre necessario assicurarsi che le dimensioni corrispondono:

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

Il compilatore rifiuta quello che hai scritto come una sciocchezza, perché int e double possono essere oggetti di diverse dimensioni. Si potrebbe ottenere lo stesso effetto in questo modo, anche se è certamente pericoloso:

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

Questa è potenzialmente pericoloso, perché se x e y sono formati differenti (diciamo int è di quattro byte e double è di otto byte) allora quando dereference gli otto byte di memoria a &x compilare y si accederà quattro byte di x e quattro byte di ... tutto ciò che viene dopo in memoria (forse l'inizio di y, o spazzatura, o qualcosa di completamente.)

Se si desidera convertire un intero ad un doppio, utilizzare un static_cast e sarà eseguire la conversione.

Se si desidera accedere alla sequenza di bit di x, gettato a qualche tipo comodo puntatore (diciamo, byte*) e l'accesso fino a sizeof(int) / sizeof(byte):

byte* p = reinterpret_cast<byte*>(&x);
for (size_t i = 0; i < sizeof(int); i++) {
  // do something with p[i]
}

reinterpretare fusione permette di reinterpretare un blocco di memoria come un tipo diverso. Questo deve essere eseguita su puntatori o riferimenti :

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

L'altra cosa è che è in realtà un cast molto pericoloso, non solo a causa di valori anomali come risultati, o l'asserzione di cui sopra non mancanza, ma perché se i tipi sono di dimensioni diverse, e si reinterpretano da ' sorgente' a 'tipi di destinazione', qualsiasi operazione sul riferimento / puntatore reinterpretato accederà byte sizeof(destination). Se sizeof(destination)>sizeof(source) allora che farà un passo oltre la memoria variabile reale, potenzialmente uccidere l'applicazione o overwritting altre variabili diverse dalla sorgente o destinazione:

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 );

reinterpret_cast è meglio utilizzato per i puntatori. Quindi un puntatore ad un oggetto può essere trasformato in un "sottomarino".

MSDN :

  

L'operatore può essere reinterpret_cast   utilizzati per le conversioni come char * a   int * o * a One_class   Unrelated_class *, che sono intrinsecamente   non sicuri.

     

Il risultato di un reinterpret_cast   Non può tranquillamente essere utilizzato per qualsiasi cosa   oltre ad essere gettato al suo   tipo di originale. Altri usi sono,   meglio, non portabile.

L'approccio cr mi ha portato giù un percorso strano con risultati incostanti. Alla fine ho trovato molto meglio memcpy come questo!

double source = 0.0;
uint64_t dest;
memcpy(&dest, &source, sizeof(dest));

Casting un int ad un doppio non richiede un cast. Il compilatore eseguirà l'assegnazione implicitamente.

Il reinterpret_cast viene utilizzato con puntatori e riferimenti, per esempio, che esprimono un int * ad un double *.

Questo è interessante. Forse si sta facendo una conversione implicita da int a stare a galla prima di tentare il cast di raddoppiare. int e galleggiano tipi tendono ad avere la stessa dimensione in byte (a seconda del sistema, naturalmente).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top