- Programmazione » Programmazione » Guida C - Manuale programmazione con articoli e risorse interessanti
Le unioni
ENTITA' COMPLESSE
Da quanto detto circa le strutture, appare evidente come esse
costituiscano uno strumento per la rappresentazione di
realtà complesse, in quanto sono in grado di
raggrupparne i molteplici aspetti quantitativi[43]. In
particolare, ogni singolo campo di una struttura permette di
gestire uno degli aspetti che, insieme, descrivono
l'oggetto reale.
Il concetto di unione deriva direttamente da quello di
struttura, ma con una importante differenza: i campi di una
union rappresentano diversi modi di vedere, o
meglio, rappresentare, l'oggetto che la union
stessa descrive. Consideriamo l'esempio seguente:
struct FarPtrWords {
unsigned offset;
unsigned segment;
};
union Far_c_Ptr {
char far *ptr;
struct FarPtrWords words;
};
La dichiarazione di un template di union è
del tutto analoga a quella di un template di struttura:
l'unica differenza è costituita dalla presenza
della parola chiave union in luogo di
struct.
La differenza è però enorme a livello
concettuale: la struct FarPtrWords comprende due
campi, entrambi di tipo unsigned int. Non ci vuole
molto a capire che essa occupa 4 byte e descrive un puntatore
di tipo "non near" , scomposto nelle due
componenti di indirizzo[44].
I due campi della union Far_c_Ptr, invece, sono
rispettivamente un puntatore a 32 bit e una struct
FarPtrWords. Contrariamente a quanto ci si potrebbe
aspettare, la union non occupa 8 byte, bensì
solo 4: puntatore e struct FarPtrWords sono due modi
alternativi di interpretarli o, in altre parole, di accedere
al loro contenuto. La union Far_c_Ptr
è un comodo strumento per gestire un puntatore come
tale, o nelle sue parti offset e segmento, a seconda della
necessità. L'area di memoria in cui il dato si
trova è sempre la stessa, ma il campo ptr la
referenzia come un tutt'uno, mentre la struttura
FarPtrWord consente di accedere ai primi due byte o
agli ultimi due, separatamente.
Si può pensare ad una union come ad un
insieme di "maschere" attraverso le quali
interpretare il contenuto di un'area di
memoria.
Vediamo la sintassi, senza preoccuparci dell'espressione
(char far *): si tratta di un cast e non
riguarda in modo diretto l'argomento
"union":
union FarPtr fp;
fp.ptr = (char far *)0xB8000000L;
printf("ptr: %Fp
" ,fp.ptr);
printf("ptr: %X:%X
" ,fp.words.segment,fp.words.offset);
L'accesso ai membri di una union segue le medesime regole dell'accesso ai membri di una struct, cioè mediante l'operatore punto (o l'operatore "freccia" se si lavora con un puntatore). E' interessante notare che inizializzando il campo ptr viene inizializzato anche il campo word, in quanto condividono la stessa memoria fisica. Il medesimo campo ptr è poi utilizzato per ricavare il valore del puntatore, mentre il campo words consente di accedere alle componenti segment ed offset. Entrambe le printf() visualizzano
B800:0000
Se nel codice dell'esempio si sostituisce la riga di inizializzazione del campo ptr con le righe seguenti:
fp.words.offset = 0;
fp.words.segment = 0xB800;
le due printf() visualizzano ancora il medesimo
output.
La sintassi che consente di accedere ai due campi della
struct FarPtrWords, a prima vista, può
apparire strana, ma in realtà essa è
perfettamente coerente con le regole esposte con riferimento
alle strutture: dal momento che ai campi di una
union si accede mediante l'operatore punto, sono
giustificate le scritture fp.ptr e fp.words
ma l'operatore punto si utilizza anche per accedere ai
membri di una struttura, perciò sono lecite le
scritture word.offset e word.segment;
ciò spiega fp.word.offset e
fp.word.segment.
Nell'esempio di union analizzato, i membri sono
due ed hanno uguale dimensione (entrambi 4 byte). Va
precisato che i membri di una union possono essere
più di due; inoltre essi possono essere di dimensioni
differenti l'uno dall'altro, nel qual caso il
compilatore, allocando la union, le riserva una
quantità di memoria sufficiente a contenere il
più "ingombrante" dei suoi membri, e li
"sovrappone" a partire dall'inizio
dell'area di memoria occupata dalla union
stessa. Esempio:
union Far_c_Ptr {
char far *ptr;
struct FarPtrWords words;
unsigned pOffset;
}
Il terzo elemento della union è un
unsigned int, e come tale occupa 2 byte. Questi
coincidono con i primi due byte di ptr (e della
struct), e rappresentano pertanto la word offset del
puntatore rappresentato dalla union.
I puntatori a union si comportano esattamente come
i puntatori a struct.
Ti potrebbe interessare anche
commenta la notizia
Chiedi alla nostra Redazione!