2016-05-23 33 views
9

Stavo leggendo su algoritmo veloce inversa radice quadrata di Carmack e notato questo:Perché qualcuno dovrebbe usare questo tipo di cast in C? Il riferimento di un galleggiante è lanciato ad un puntatore a int e quindi dereferenziato

float x; 
// ... // 
int i = *(int*)&x; 

Perché qualcuno scegliere di utilizzare questo tipo bizzarro di lanciare invece di solo il seguente?

int i = (int)x; 
+3

Carmack non ha effettivamente scrivere l'algoritmo ; vedere la [pagina Wiki] (https://en.wikipedia.org/wiki/Fast_inverse_square_root#History_and_investigation). – DylanSp

risposta

28

Questo è diverso.

int i = (int) x; invierà float a int, che verrà semplicemente troncato.

int i = *(int *) &x; caricherà in i gli stessi bit attualmente memorizzati in x. Il risultato è qualcosa di completamente diverso dal troncamento di x.

+1

E perché scegliere le seconde opzioni? L'unica ragione per cui posso pensarci è che vogliono manipolare direttamente la rappresentazione bit di un float. – Giorgio

+10

Questa è l'idea che penso. – aragaer

+2

Sì, questa è l'idea. Ero curioso dal momento che mi sembra un'idea piuttosto inutile a meno che tu non conosca già il formato float caratteristico/mantissa, ma https://en.wikipedia.org/wiki/Fast_inverse_square_root lo spiega. –

15

Si chiama type punning. Interpreterà lo float come int. Significato, la rappresentazione del bit è esattamente copiata.

È un'operazione potenzialmente pericolosa, dal momento che alcune rappresentazioni di bit di interi in virgola mobile potrebbero essere rappresentazioni di trap come numeri interi (non il caso con IEEE-754 float e 2s complementari agli interi, sebbene).

Inoltre, potrebbe non funzionare più, a causa del comportamento non definito come da standard C. Sta violando la rigida regola dell'aliasing.

C supporta solo l'accesso a variabili di un tipo diverso tramite memcpy.

Questo è il modo valido di serie C di scrivere l'operazione:

int y; float x = 42.0f; 
memcpy(&y, &x, sizeof(x)); 

C99 ha aggiunto un altro modo di fare questo, utilizzando un union:

union { int y; float x; } u = { .x = 42.0f }; 
int y = u.y; 
+0

La cosa del sindacato non viola anche il rigoroso aliasing? – Random832

+0

@ Random832 Dipende dallo standard C che si sta utilizzando. Dal momento che C99, non è più una violazione. Dal momento che la maggior parte dei compilatori in qualche modo lo ha permesso anche in precedenza, lo standard lo ha reso ufficiale. – Leandros

+0

Sono curioso di sapere se c'è una differenza di prestazioni tra i due approcci (tipo punning vs unions). – Dai

Problemi correlati