Barninga Z
a- a+

Le unioni

ENTITA' COMPLESSE 

Le unioni 

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

C'è 1 commento
Redazione
Ti interessano altri articoli su questo argomento?
Chiedi alla nostra Redazione!