2011-12-15 11 views
10

Si prega di considerare il seguente codice:evitano con memcpy

float float_value = x; // x is any valid float value 
int int_value = 0; 
size_t size = sizeof(int) < sizeof(float) ? sizeof(int) : sizeof(float); 
memcpy(&int_value, &float_value, size); 

Per quanto so che questo potrebbe comportare una rappresentazione trappola. Le mie domande:

  1. È vero?
  2. Se no, perché?
  3. In caso contrario, esiste un altro modo per evitare una possibile rappresentazione di trap?
+0

Sembra sostanzialmente un comportamento non definito del male. Int e float possono essere di dimensioni diverse. Cosa stai cercando di realizzare? – EvilTeach

+2

Stai cercando di vedere la rappresentazione binaria di un float? memcpy() è una soluzione di bomba nucleare in cui farebbe il semplice martello di un assegnatario con un typecast. –

+1

È possibile utilizzare un int unsigned ed evitare problemi. – TJD

risposta

10

Il modo sanzionato che non produrrà alcuna dichiarazione trappola è

unsigned char obj[sizeof float]; 
memcpy(obj, &float_value, sizeof float); 

quindi è possibile utilizzare i byte della rappresentazione dell'oggetto per costruire il tuo desiderato int.

Tuttavia, l'utilizzo di numeri interi a larghezza fissa come indicato da Stephen Canon è migliore, a meno che non si disponga di una strana dimensione float.

+0

C99: http://blackshell.com/~msmud/cstd.html#6.2.6.1 – u0b34a0f6ae

+0

In realtà, per lo scopo specifico dell'hashing, mi piace molto questa soluzione. –

+0

@ kaizer.se Grazie per il collegamento allo standard. –

2

Sì, ciò potrebbe causare una rappresentazione di trap. Per quanto riguarda come evitarlo:

  • affermare che sizeof(int32_t) == sizeof(float)
  • Uso int32_t invece di int.

I tipi di interi a larghezza fissa potrebbero non ammettere rappresentazioni di trap. Nello specifico, lo standard richiede che non abbiano bit di riempimento e che non sia possibile avere una rappresentazione trap senza padding.

+0

ne sei sicuro? io però solo * char senza segno * non intrappola mai. potresti citare C99? Grazie per la risposta! – Johannes

+0

@Johannes: §7.18.1.1 "Il nome typedef intN_t designa un tipo intero con segno con larghezza N, nessun bit di riempimento e una rappresentazione di complemento a due." Poiché non ci sono bit di riempimento, tutti gli N bit sono * valore * bit, quindi ogni combinazione di bit ha un valore definito dallo standard e non può essere una rappresentazione di trap. –

+0

@Stephen, potresti avere una rappresentazione trap senza padding, ovvero le restrizioni che citi lasciano ancora due possibili valori per 'INTXX_MIN'. Ma lo standard chiude questa scappatoia fissando ciò che il valore deve essere in aggiunta. Nella copia ho anche sembra che questo è stato aggiunto in seguito con uno degli aggiornamenti. –

3

Non è necessario memcpy se si desidera solo verificare i valori lì. Il metodo più semplice è quello di lanciare solo

unsigned char const* p = &float_object; 

puntatore getto a tutti i tipi char è sempre garantita a dare qualcosa di valido con il quale si può fare semplice aritmetica. Sei sicuro finché fai il dereferenziamento entro i limiti dati dalla dimensione di float_object.

Se si desidera considerare che come numero il più sicuro è scegliere un numero intero senza segno di larghezza fissa, molto probabilmente uint32_t. Se sai che i requisiti di larghezza sono soddisfatti, questo dovrebbe darti tutto ciò di cui hai bisogno.

Come accennato, questo funziona bene finché non si scrive attraverso quel puntatore. Quindi le regole di aliasing per i puntatori possono fare in modo che l'ottimizzatore vada in errore.