Ricerca…
introduzione
I campi di bit racchiudono saldamente le strutture C e C ++ per ridurre le dimensioni. Ciò sembra indolore: specificare il numero di bit per i membri e il compilatore esegue il lavoro di bit di co-mingling. La restrizione è l'impossibilità di prendere l'indirizzo di un membro di campo bit, poiché è memorizzato insieme. sizeof()
è anche non consentito.
Il costo dei campi bit è un accesso più lento, poiché la memoria deve essere recuperata e le operazioni bit a bit vengono applicate per estrarre o modificare i valori dei membri. Queste operazioni si aggiungono anche alla dimensione dell'eseguibile.
Osservazioni
Quanto sono costose le operazioni bit a bit? Supponi una semplice struttura di campo non bit:
struct foo {
unsigned x;
unsigned y;
}
static struct foo my_var;
In qualche secondo codice:
my_var.y = 5;
Se sizeof (unsigned) == 4
, allora x viene memorizzato all'inizio della struttura, e y è memorizzato in 4 byte. Il codice di assembly generato può essere simile a:
loada register1,#myvar ; get the address of the structure
storei register1[4],#0x05 ; put the value '5' at offset 4, e.g., set y=5
Questo è semplice perché x non è mescolato a y. Ma immagina di ridefinire la struttura con i campi di bit:
struct foo {
unsigned x : 4; /* Range 0-0x0f, or 0 through 15 */
unsigned y : 4;
}
Sia x
che y
saranno allocati a 4 bit, condividendo un singolo byte. La struttura occupa quindi 1 byte, invece di 8. Considerare l'assembly per impostare y
ora, assumendo che finisca nel nibble superiore:
loada register1,#myvar ; get the address of the structure
loadb register2,register1[0] ; get the byte from memory
andb register2,#0x0f ; zero out y in the byte, leaving x alone
orb register2,#0x50 ; put the 5 into the 'y' portion of the byte
stb register1[0],register2 ; put the modified byte back into memory
Questo può essere un buon compromesso se abbiamo migliaia o milioni di queste strutture, e aiuta a mantenere la memoria nella cache o impedisce lo swapping, o potrebbe gonfiare l'eseguibile per peggiorare questi problemi e rallentare l'elaborazione. Come con tutte le cose, usa il buon senso.
Uso del driver di dispositivo: evitare campi di bit come strategia di implementazione intelligente per i driver di dispositivo. I layout di archiviazione dei campi a bit non sono necessariamente coerenti tra i compilatori, rendendo tali implementazioni non portabili. La lettura-modifica-scrittura per impostare valori non può fare ciò che i dispositivi si aspettano, causando comportamenti imprevisti.
Dichiarazione e uso
struct FileAttributes
{
unsigned int ReadOnly: 1;
unsigned int Hidden: 1;
};
Qui, ciascuno di questi due campi occuperà 1 bit in memoria. È specificato da : 1
espressione dopo i nomi delle variabili. Il tipo base del campo di bit può essere qualsiasi tipo integrale (int a 8 bit int a 64 bit). Si consiglia di utilizzare il tipo unsigned
, altrimenti potrebbero verificarsi sorprese.
Se sono necessari più bit, sostituire "1" con il numero di bit richiesto. Per esempio:
struct Date
{
unsigned int Year : 13; // 2^13 = 8192, enough for "year" representation for long time
unsigned int Month: 4; // 2^4 = 16, enough to represent 1-12 month values.
unsigned int Day: 5; // 32
};
L'intera struttura utilizza solo 22 bit, e con normali impostazioni del compilatore, sizeof
questa struttura sarebbe 4 byte.
L'utilizzo è piuttosto semplice. Basta dichiarare la variabile e usarla come una struttura ordinaria.
Date d;
d.Year = 2016;
d.Month = 7;
d.Day = 22;
std::cout << "Year:" << d.Year << std::endl <<
"Month:" << d.Month << std::endl <<
"Day:" << d.Day << std::endl;