2010-04-30 16 views
7

Ultimamente sto lavorando a questa piattaforma per la quale un codebase legacy emette un gran numero di avvisi di "cast aumenta l'allineamento richiesto a N", dove N è la dimensione della destinazione del cast.Avviso: il cast aumenta l'allineamento richiesto

struct Message 
{ 
    int32_t id; 
    int32_t type; 
    int8_t data[16]; 
}; 

int32_t GetMessageInt(const Message& m) 
{ 
    return *reinterpret_cast<int32_t*>(&data[0]); 
} 

Speriamo che sia ovvio che un'implementazione "reale" sarebbe un po 'più complesso, ma il punto fondamentale è che ho i dati provenienti da qualche parte, ho sanno che è allineato (perché ho bisogno del id e type per essere allineati), eppure ottengo il messaggio che il cast sta aumentando l'allineamento, nel caso di esempio, a 4.

Ora so che posso sopprimere l'avviso con un argomento al compilatore, e so che posso gettare il bit tra parentesi per annullare * prima, ma non voglio veramente passare attraverso ogni bit di codice che necessita di questo tipo di manipolazione (c'è molto perché cariciamo un sacco di dati una parte del disco, e che i dati arrivano come char buffer in modo che possiamo facilmente puntare-anticipo), ma qualcuno può darmi qualche altra idea su questo problema? Voglio dire, per me sembra un'opzione così importante e comune che non vorresti avvertire, e se c'è effettivamente la possibilità di sbagliare, sopprimere l'avvertimento non aiuterà. Infine, il compilatore non può sapere come faccio a fare in modo che l'oggetto in questione sia effettivamente allineato nella struttura, quindi dovrebbe essere in grado di non preoccuparsi dell'allineamento su quell'oggetto particolare a meno che non sia stato colpito un byte o due?

+0

C'è una sorta di pragma/direttiva imballato il tuo compilatore supporta per far sapere che la struttura è allineata con x-byte? –

+0

"questa piattaforma", non farci indovinare. –

+0

@ Hans- Non posso condividere dettagli specifici della piattaforma. @ Michael- Posso andare in giro e iniziare a taggare le cose come allineate, cosa che ho iniziato a fare, ma il problema è ovunque. La domanda non è tanto "come la risolvo", ma piuttosto "perché il compilatore si preoccupa così tanto quando ha tutte le informazioni di cui ha bisogno". Per esempio. non avverte che potrei dereferenziare gli altri membri non allineati ... –

risposta

4

Una possibile alternativa potrebbe essere:

int32_t GetMessageInt(const Message& m) 
{ 
    int32_t value; 
    memcpy(&value, &(data[0]), sizeof(int32_t)); 
    return value; 
} 

Per l'architettura x86, l'allineamento non sta andando alla materia più di tanto, è più un problema di prestazioni che non è davvero rilevante per il codice che avete fornito. Per altre architetture (es. MIPS) gli accessi disallineati causano eccezioni CPU.


OK, ecco un'altra alternativa:

struct Message 
{ 
    int32_t id; 
    int32_t type; 
    union 
    { 
     int8_t data[16]; 
     int32_t data_as_int32[16 * sizeof(int8_t)/sizeof(int32_t)]; 
     // Others as required 
    }; 
}; 

int32_t GetMessageInt(const Message& m) 
{ 
    return m.data_as_int32[0]; 
} 

Ecco variazione di quanto sopra che include i suggerimenti da cpstubing06:

template <size_t N> 
struct Message 
{ 
    int32_t id; 
    int32_t type; 
    union 
    { 
     int8_t data[N]; 
     int32_t data_as_int32[N * sizeof(int8_t)/sizeof(int32_t)]; 
     // Others as required 
    }; 
    static_assert((N * sizeof(int8_t) % sizeof(int32_t)) == 0, 
        "N is not a multiple of sizeof(int32_t)"); 
}; 

int32_t GetMessageInt(const Message<16>& m) 
{ 
    return m.data_as_int32[0]; 
} 


// Runtime size checks 
template <size_t N> 
void CheckSize() 
{ 
    assert(sizeof(Message<N>) == N * sizeof(int8_t) + 2 * sizeof(int32_t)); 
} 

void CheckSizes() 
{ 
    CheckSize<8>(); 
    CheckSize<16>(); 
    // Others as required 
} 
+0

Sì, è una piattaforma che attiverà eccezioni di lettura non allineate a meno che non contrassegni l'oggetto come non allineato. Certamente potrei copiare i dati ma sembra eccessivo; se leggo un file fuori dal disco che riempie la memoria, voglio solo dire "questo è qui, questo è qui, questo è qui" e non è necessario che ci sia qualcosa che non si guadagna. –

+1

@ dash-tom-bang: dipende dal compilatore, ovviamente, ma si potrebbe ottenere che 'memcpy' per il prezzo di un non allineato (per quanto sa il compilatore)' int32_t' letto.Ad esempio, GCC è abbastanza bravo in questo genere di cose, può ottimizzare le variabili nei registri anche se si prende un indirizzo, a patto di non passare l'indirizzo a un codice non in linea. –

+0

Non credo che la copiatura farebbe un'enorme differenza se il tuo compilatore ha un intrinseco "memcpy" decente. – msandiford

Problemi correlati