2013-09-06 13 views
10

Sto lavorando all'analisi del flusso di dati di rete, mi chiedo se non sia possibile mappare il flusso di dati direttamente alla struttura dati.C'è un modo per controllare il padding tra i membri della struct (incluso il campo di bit) in C++?

Ad esempio, voglio definire la struttura dati per un protocollo RTP come segue.

class RTPHeader 
{ 
    int version:2; // The first two bits is version. 
    int P:1; // The next bits is an field P. 
    int X:1; 
    int CC:4; 
    int M:1; 
    int PT:7; 
    int sequenceNumber; 
    int64 timestamp; 
    ..... 
}; 

e di utilizzarlo in questo modo.

RTPHeader header; 
memcpy(&header, steamData, sizeof(header)); 

Ma, come il compilatore C++ inserirà imbottitura tra i membri, non v'è alcun modo per controllare che in modo che nessun padding vengono aggiunti tra i membri (tra cui i membri del campo di bit)?

Questa domanda NON è un duplicato di How to get rid of padding bytes between data members of a struct perché nel mio esempio ci possono essere campi di bit.

+0

Credo non ci sia un modo standard per farlo, ma il compilatore potrebbe avere qualche estensione (ad es. VS ce l'ha) che ti permette di controllare il riempimento. Spero che qualcuno mi smentisca. –

+0

I bitfield si sommano a un multiplo di 8, (non sorprendentemente). Se si ordina al compilatore di comprimere la classe/struct, si dovrebbe essere OK. –

+3

Non penso che il padding sia aggiunto tra bitfield, vero? Sarebbe in qualche modo sconfiggere il punto di bitfield altrimenti. –

risposta

3

Finché non è necessario che questo codice "funzioni" su macchine arbitrarie - ad es. macchine che hanno restrizioni su ciò che i confini di un int siede su (in genere un limite di 4 Byte) Byte, quindi utilizzando

#pragma(pack) 

dovrebbe funzionare, ed è supported in GCC così come Microsoft e "Microsoft Plug in compatibili" compilatori (come come compilatore di Intel).

Tuttavia, notare che l'accesso non allineato non è supportato su tutti i processori, quindi l'avvio di un blocco con un valore a 16 bit, seguito da una 32 bit potrebbe causare problemi.

Vorrei anche usare un intero di dimensioni per il sequencenumber per assicurarmi che sia a 32 bit in OGNI compilatore, e non improvvisamente a 16 o 64 bit.

Si noti inoltre che lo standard C++ non indica nulla sull'ordine in cui i bit sono archiviati in un campo bit - o, di conseguenza, se vi sono degli spazi vuoti tra loro o meno. Sebbene ci si possa aspettare che i bitfield vengano archiviati secondo l'ordine dei byte (le macchine little endian iniziano con i bit più bassi per primi, le macchine big endian iniziano prima con i bit più alti), lo standard non dice nulla a riguardo.

+0

Contrassegnerò questo post come risposta, perché non solo risponde alla domanda, ma sottolinea anche che i field store bit non sono definiti in C++ e anche il problema little endian. In realtà dopo aver considerato il problema di endian, mi piacerebbe non scegliere questa soluzione per analizzare il flusso. – ZijingWu

3

per evitare un inserimento di byte imbottiti è possibile utilizzare

#pragma pack(push,n) // use n = 1 to have 1 Byte resolution 

typedef struct {...}MY_STRUCT; 

#pragma pack(pop) 

questo ha funzionato bene per me.

Considera anche le opzioni di compilazione per la struct Stati allineamento

/Zp1 

Ma tenere a mente che questo avrà un impatto per l'intero progetto.

+1

Tuttavia questa è un'estensione del compilatore dipendente dalla piattaforma (anche se gcc e VS usano la stessa sintassi per esso, non lo so). E l'opzione della riga di comando è sicuramente solo VS. –

7

Se si è in grado di utilizzare C++ 11, è possibile sfruttare il controllo di allineamento implementato con l'operatore alignof.

Se non è possibile utilizzare un compilatore C++ 11, esistono alternative non standard che possono essere d'aiuto; in GCC __attribute__(packed) e con MSVC #pragma pack.

Se la scelta è la variante GCC, l'attributo deve essere posizionato alla fine della struct:

class RTPHeader 
{ 
    int version:2; // The first two bits is version. 
    int P:1; // The next bits is an field P. 
    int X:1; 
    int CC:4; 
    int M:1; 
    int PT:7; 
    int sequenceNumber; 
    int64 timestamp; 
    ..... 
} __attribute__((packed)) ; // attribute here! 

Se la scelta è la MSVC uno, il pragma deve essere posto prima la struct:

#pragma pack(1) // pragma here! 
class RTPHeader 
{ 
    int version:2; // The first two bits is version. 
    int P:1; // The next bits is an field P. 
    int X:1; 
    int CC:4; 
    int M:1; 
    int PT:7; 
    int sequenceNumber; 
    int64 timestamp; 
    ..... 
}; 

Se il codice deve essere compilato in entrambi, l'unico modo (senza C++ 11 alignof operatore) è la compilazione condizionale:

#ifdef MSVC 
#pragma pack(1) 
#endif 
class RTPHeader 
{ 
    int version:2; // The first two bits is version. 
    int P:1; // The next bits is an field P. 
    int X:1; 
    int CC:4; 
    int M:1; 
    int PT:7; 
    int sequenceNumber; 
    int64 timestamp; 
    ..... 
#ifdef GCC 
}__attribute__((packed)); 
#else 
}; 
#endif 
Problemi correlati