- Programmazione » Programmazione » Guida C - Manuale programmazione con articoli e risorse interessanti
I campi di bit
ENTITA' COMPLESSE
Se una variabile di tipo intero può assumere solo un
limitato numero di valori, è teoricamente possibile
memorizzarla utilizzando un numero di bit inferiore a quello
assegnatole dal compilatore: basta infatti 1 bit per
memorizzare un dato che può assumere solo due valori,
2 bit per un dato che può assumere quattro valori, 3
bit per uno che può assumere otto valori, e
così via.
Il C non ha tipi intrinseci di dati con un numero di bit
inferiori a 8 (il char), ma consente di
"impaccare" più variabili nel numero di bit
strettamente necessario mediante i cosiddetti campi di
bit.
Un esempio di uso di questo strumento può essere
ricavato con riferimento alla gestione di una cartella
clinica. Supponiamo di voler gestire, per ogni paziente, le
seguenti informazioni: il sesso (maschile o femminile), lo
stato vitale (vivente, defunto, in coma), il tipo di
medicinale somministrato (sedici categorie, come antibiotici
e sulfamidici), la categoria di ricovero (otto possibili
sistemazioni, da corsia a camera di lusso). In questa ipotesi
sarebbe possibile codificare il sesso mediante un solo bit,
lo stato vitale con 2, il tipo di cura con 4, la sistemazione
in ospedale con 3: in totale 10 bit, senz'altro
disponibili in un'unica variabile di tipo
intero.
L'uso dei campi di bit prevede la dichiarazione di un
template: anche in questo caso la somiglianza con le
strutture è palese.
struct CartellaClinica {
unsigned sesso: 1;
unsigned stato: 2;
unsigned cura: 4;
unsigned letto: 3;
};
La dichiarazione utilizza la parola chiave struct,
proprio come se si trattasse di un template di struttura; le
dichiarazioni dei campi sono introdotte da uno specificatore
di tipo e chiusa dal punto e virgola; la differenza qui
consiste nell'indicazione dell'ampiezza in bit di
ogni singolo campo, effettuata posponendo al nome del campo
il carattere due punti (":")
seguito dal numero di bit da assegnare al campo stesso. I due
punti servono, infatti, a indicare la definizione di un campo
di bit, la cui ampiezza viene specificata dal numero
seguente; se il numero totale di bit non è disponibile
in un'unica variabile intera, il compilatore alloca anche
la successiva word in memoria.
I campi di bit del tipo CartellaClinica sono tutti
dichiarati unsigned int: in tal modo tutti i bit
sono utilizzabili per esprimere i valori che di volta in
volta i campi stessi assumeranno. In realtà, i campi
di bit possono anche essere dichiarati int, ma in
questo caso il loro bit più significativo rappresenta
il segno e non è quindi disponibile per memorizzare il
valore. Un campo dichiarato int ed ampio un solo bit
può esprimere solo i valori 0 e
1.
I campi di bit sono referenziabili esattamente come i campi
di una comune struttura:
enum SEX {
maschile,
femminile
};
struct CartellaClinica {
unsigned sesso: 1;
unsigned stato: 2;
unsigned cura: 4;
unsigned letto: 3;
};
char *sessi[] = {
"MASCHILE" ,
"FEMMINILE"
};
....
struct CartellaClinica Paziente;
....
Paziente.sesso = maschile;
....
printf("Sesso del paziente: %s
" ,sessi[Paziente.sesso]);
E' importante ricordare come sia compito del
programmatore assicurarsi che i valori memorizzati nei campi
di bit non occupino più bit di quanti ne sono stati
loro riservati in fase di definizione del template, dal
momento che le regole del C non assicurano che venga
effettuato un controllo nelle operazioni di assegnamento di
valori ai campi. Se si assegna ad un campo di bit un valore
maggiore del massimo previsto per quel campo, può
accadere che i bit più significativi di quel valore
siano scritti nei campi successivi: è bene, ancora una
volta, verificare il comportamento del proprio
compilatore.
Naturalmente un campo di bit può essere utilizzato
anche per memorizzare un'informazione di tipo
quantitativo: ad esempio, la struct CartellaClinica
potrebbe essere ridefinita mediante l'aggiunta di un
campo atto a memorizzare il numero di ricoveri subiti dal
paziente; impiegando 6 bit tale valore è limitato a
63.
struct CartellaClinica {
unsigned sesso: 1;
unsigned stato: 2;
unsigned cura: 4;
unsigned letto: 3;
unsigned ricoveri: 6;
};
Nella nuova definizione, tutti i 16 bit delle due word occupate in memoria dalla struct CartellaClinica sono utilizzati.