2015-03-20 14 views
6

Ho bisogno di creare una struttura con bitfield per incapsulare alcuni dati provenienti dall'hardware. Supponendo Uso meccanismi specifici compilatore per applicare l'imballaggio e l'ordinazione, è possibile creare una struttura simile alla seguente (non sintatticamente corretto):Campi bit nidificati in C/C++

typedef struct _BYTE_OF_DATA 
{ 
    uint8_t Reserved1 : 2; 
    struct 
    { 
     uint8_t BitWithSomeMeaning : 1; 
     uint8_t BitWithSomeOtherMeaning : 1; 
    } BitsWithMeaning; 
    uint8_t Reserved2 : 4; 
} BYTE_OF_DATA, *PBYTE_OF_DATA; 

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size"); 

che possono poi essere letta come segue:

BYTE_OF_DATA byteOfData; 

byteOfData.Reserved1 = 1; 
byteOfData.BitsWithMeaning.BitWithSomeOtherMeaning = 0; 

Lo schema esatto che ho descritto sopra non funzionerà, perché suppongo che la struttura BitsWithMeaning debba iniziare a un limite di byte. Mi stavo chiedendo se c'è qualche altro trucco con cui posso ottenere questo "annidamento" di bitfield.

+3

Sono consentiti i macro? Questo è C++ o C? Penso al C++ perché non penso che C abbia 'static_assert'. –

+0

Poiché esiste un 'static_assert', suppongo che debba essere C++, quindi il tag C dovrebbe probabilmente essere rimosso. –

+2

C ha 'static_assert' dal C11. E la domanda potrebbe anche essere rilevante per C. – Morwenn

risposta

6

Per elaborare il commento precedente, qualcosa del genere dovrebbe consentire lo stile di accesso desiderato. Anche se in tutt'altro modo elegante:

typedef union _BYTE_OF_DATA { 
    struct { 
     uint8_t Reserved1 : 2; 
     uint8_t : 2; 
     uint8_t Reserved2 : 4; 
    }; 
    struct { 
     uint8_t : 2; 
     uint8_t BitWithSomeMeaning : 1; 
     uint8_t BitWithSomeOtherMeaning : 1; 
     uint8_t : 4; 
    } BitsWithMeaning; 
} BYTE_OF_DATA, *PBYTE_OF_DATA; 

Personalmente preferirei di gran lunga maschera tradizionale campo e posizione costanti e manipolare i registri manualmente. La mia esperienza è che l'accesso a campi di bit I/O volatili in questo stile porta inevitabilmente a un codice inefficiente e soggetto a rischio di competizione.

+0

In suvated, perché questo effettivamente raggiunge il tipo di accesso che voglio eseguire. Tuttavia, come hai detto, questo rende la struttura stessa illeggibile; non è immediatamente evidente quale sia la struttura del registro. – TripShock

+0

L'identificativo '_BYTE_OF_DATA' è riservato all'implementazione (in C e C++). In C++ non ti preoccuperai nemmeno di 'typedef'. – MSalters

+0

@MSalters: la denominazione è stata trasferita dalla domanda originale e in ogni caso c'è una buona possibilità che questa sia l'implementazione. Questo tipo di definizioni di registro I/O si incontrerebbero più frequentemente come parte delle intestazioni di dispositivo di un compilatore C/C++ incorporato. – doynax

1

Si dovrebbe usare un'unione in questo caso

typedef union _BYTE_OF_DATA { 
    uint8_t data; 
    struct { 
     uint8_t padding1 : 2; 
     uint8_t BitWithSomeMeaning : 1; 
     uint8_t BitWithSomeOtherMeaning : 1; 
     uint8_t padding 2 : 4; 
    } BitsWithMeaning; 
} BYTE_OF_DATA, *PBYTE_OF_DATA; 

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size"); 

in modo da poter compilare i dati in un solo colpo:

BYTE_OF_DATA myByte; 

myByte.data = someotherbyte; 

E ottenere po 'di significato:

int meaning1 = myByte.BitWithSomeMeaning; 
int meaning2 = myByte.BitWithSomeOtherMeaning; 

O fare il contrario:

myByte.data = 0; // Put all fields to 0 

myByte.BitWithSomeMeaning = 1; 
myByte.BitWithSomeOtherMeaning = 0; 

int data = myByte.data; 
0

In C++, la soluzione più semplice potrebbe essere

struct BYTE_OF_DATA 
{ 
    uint8_t bits; 
    private: 
    struct 
    { 
     bool getBitWithSomeMeaning() const { return bool(bits&0x20); } 
     bool getWithSomeOtherMeaning() const { return bool(bits&0x10); } 
     void setBitWithSomeMeaning(bool b); 
     void setWithSomeOtherMeaning(bool b); 
    } BitsWithMeaning; 
}; 

Nessun getter/setter per i campi riservati ovviamente. Ctor probabilmente dovrebbe impostare quei campi su 0 o 1, come specificato dal protocollo.

Problemi correlati