2009-10-13 17 views

risposta

18

Questo è il problema con un cast in stile C. Devi guardare da vicino per vedere cosa stai ricevendo. Nel tuo caso "(int)" era un normale cast statico. Il valore viene convertito in un int tramite troncamento. Nel tuo caso "(int &)" è stato un cast reinterpretato. Il risultato è un lvalue che si riferisce alla posizione di memoria di b ma è trattato come un int. In realtà è una violazione delle rigide regole di aliasing. Quindi, non essere sorpreso se il tuo codice non funzionerà più dopo aver attivato tutte le ottimizzazioni.

codice equivalente con C++ stile getta:

float b = 1.0f; 
int i = static_cast<int>(b); 
int& j = reinterpret_cast<int&>(b); 
cout<<i<<endl; 
cout<<j<<end; 

Controlla il tuo libro preferito C++ su questi tipi di calchi.

+0

Sì, è una grande risposta. Ma ricevo ancora una domanda. Perché un errore, "errore: static_cast non valido dal tipo 'float' per digitare 'int &'", è successo quando ho usato static_cast per lanciare un float su int e mi piace "float b = 1.0f; int & j = static_cast b;". Non ho trovato i limiti di static_cast nel mio libro C++ favoraite, "The C++ Programming Language". – toby

+3

Questa è la protezione ottenuta dall'uso di cast di stile C++. Se il compilatore accetta una probabilità static_cast, non stai facendo nulla di sbagliato. Le uniche cose non sicure che un cast statico ti consente è una conversione non controllata da Base */Base e Derivata */Derivata e annullata * a T * per quanto posso ricordare. In pratica, è in grado di invertire le conversioni implicite, non di più, senza contare le conversioni const. – sellibitze

+0

Ciao, sellibitze, grazie per il tuo aiuto! Capito! – toby

1

Sembra che si stia tentando di creare un riferimento int a un float utilizzando il cast (int &). Ciò non funzionerà poiché i float sono rappresentati in modo diverso da int. Questo non funzionerà.

Se la rappresentazione di float e int sono uguali, potrebbe aver funzionato.

2
float b = 1.0f; 
... 
int& j = (int&)b; 

Nella seconda conversione, stai guardando lo spazio di memoria che contiene b come se fosse uno spazio di memoria che contiene un int. I valori in virgola mobile vengono memorizzati in modo completamente diverso come numeri interi, quindi i risultati sono davvero diversi ...

11

In esadecimale 1065353216 è 0x3F800000. Se lo interpreti come numero in virgola mobile a 32 bit, ottieni 1.0. Se si scrive fuori in binario si ottiene questo:

 
3 F 8 0 0 0 0 0 
0011 1111 1000 0000 0000 0000 0000 0000 

o raggruppate in modo diverso:

 
0 01111111 00000000000000000000000 
s eeeeeeee vvvvvvvvvvvvvvvvvvvvvvv 

Il primo bit (s) è il bit di segno, i successivi 8 bit (e) sono l'esponente e gli ultimi 23 bit (v) sono il significato e. "L'esponente a virgola mobile in virgola mobile a precisione singola viene codificato utilizzando una rappresentazione binaria offset, con l'offset zero pari a 127, noto anche come bias esponenziale nel IEEE 754 standard". Interpretando questo si vede che il segno è 0 (positivo), l'esponente è 0 (01111111 b = 127, lo "spostamento zero"), e il significato è 0. Questo ti dà +0 che è 1.0.

In ogni caso, ciò che sta accadendo è che si sta prendendo un riferimento a un float (b) e reinterpretandolo come riferimento (int&). Quindi quando leggi il valore di j ottieni i bit da b. Interpretato come float, questi bit significano 1.0, ma interpretati come int quei bit significano 1065353216.

Per quello che vale, non ho mai usato un cast utilizzando & come (int&). Non mi aspetto di vederlo o usarlo in qualsiasi normale codice C++.

+0

Ehi, c'è un errore di battitura qui, (v) è ripetuto due volte, corregge il primo (v) in (e). – legends2k

+0

Ho letto il codice assembly generato da g ++. Questo è esattamente l'accadere nel programma. – toby

2

In questo caso particolare la conversione in questione non ha significato.Si tratta di un tentativo di reinterpretare la memoria occupata da un oggetto float e da un valore int. Questo è esplicitamente illegale in C/C++, il che significa che produce un comportamento non definito. Comportamento indefinito: questo è l'unico significato che ha in questo caso.

1

Cosa avevi intenzione di fare? La stessa cosa:

float b = 1.0f; 
int i = (int) b; 
int* j = (int*)b;//here we treat b as a pointer to an integer 
cout<<i<<endl; 
cout<<(*j)<<endl; 

come risolvere il problema:

float b = 1.0f; 
int i = (int) b; 
int castedB = (int)b;//static_cast<int>(b); 
int& j = castedB; 
cout<<i<<endl; 
cout<<j<<endl;