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;


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow