2012-04-03 15 views
5

Ho una struttura che mira a memorizzare i dati definiti dall'utente (cioè da un plugin). Ha un tale char[] con una data dimensione massima per memorizzare quei dati.Tipo punning, char [] e dereferencing

struct A 
{ 
    // other members omitted 
    // data meant to be type punned, only contains PODs 
    char data[256]; 
}; 

Poi c'è una struttura utente di esempio che ha una funzione statica di lanciare se stesso da A.

struct B 
{ 
    int i; 
    double d; 

    static B& FromA_ref(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return * reinterpret_cast<B*>(a.data); 
    } 
}; 

posso compilare con g++ -O3 -std=c++0x -Wall -o test test.cpp (GCC 4.6.1).

Avvia un avviso dereferencing type-punned pointer will break strict-aliasing rules. Ho pensato che sarebbe ok visto che ho usato uno storage char[] che pensavo avrebbe seguito le stesse regole di char*. Trovo strano che non sia così. Non è vero? Beh, non posso cambiarlo adesso, quindi andiamo avanti.

Consideriamo ora il seguente metodo:

struct B 
{ 
    .... 
    static B* FromA_ptr(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return reinterpret_cast<B*>(a.data); 
    } 
} 

Dato che non sono dereferenziazione nulla qui GCC non emette alcun preavviso. Né lo fa quando uso il mio puntatore su B in seguito.

A a; 
auto b = B::FromA_ptr(a); 
b->i = 2; // no warnings. 

Ma è sicuro farlo? Mi sembra di aver lavorato su questo problema piuttosto che risolverlo. Per me -> sta ancora dereferenziando la variabile in qualche modo.

In alternativa, esiste un modo migliore per ottenere l'effetto? OSSIA ottenere un riferimento modificabile (o puntatore) castato da una memoria all'interno di un'altra struttura? (Union non funzionerà poiché il set di tipi memorizzati non è noto quando A è definito e alcuni possono essere aggiunti tramite plug-in, memcpy mi costringerà a copiare i dati avanti e indietro anche se sembra essere l'unico modo sicuro lontano)

+0

Non sono esperto, ma stai cercando l'attributo '__may_alias__'? http://blog.worldofcoding.com/2010/02/solving-gcc-44-strict-aliasing-problems.html –

+0

Ad ogni modo, come gestisci il problema dell'allineamento? – curiousguy

+0

@curiousguy: finora non lo faccio ma dovrei. Su x86 immagino che potrei peggiorare le prestazioni nel peggiore dei casi, comunque. Spero che __attribute __ ((align (8))); sia sufficiente poiché non sto cercando di vettorizzare automaticamente nulla. Probabilmente, 'may_alias' dice già a GCC di prestare attenzione all'allineamento prima di fare troppe cose strane. –

risposta

3

La risposta è no, non è sicuro (vedi questo SO question)

GCC assumerà che i puntatori non può alias. Ad esempio, se si assegna attraverso uno e poi si legge dall'altro, GCC può, come ottimizzazione, riordinare la lettura e la scrittura - ho visto accadere questo nel codice di produzione, non è piacevole eseguire il debug.

attributo ((may_alias)) sui tipi utilizzati è probabilmente il più vicino si può arrivare a disabilitare il presupposto per una particolare sezione di codice.