Per introdurvi l'argomento (e, ripeto, leggete senza consultare prima un manuale del C, se no non potete mettervi alla prova), vi racconterò una storia vera. Un tipo che conosco, le cui iniziali sono A.A. (di più non posso dirvi per questioni di privacy) andò, molto tempo fa, a un colloquio di lavoro, e gli proposero un semplice test come questo (più o meno):
Ecco, per i motivi indicati all'inizio del post (uso dubbio e infrequente), il nostro amico che non usava una union da almeno 15 anni (si, 15 anni!), rimase inizialmente perplesso, sforzò la memoria e non cadde nel 1º livello di errore che induce questo test un po' ingannevole, 1º livello di errore che ti indurrebbe a dire:#include <stdio.h> void main(void) { union u_test { int i; char s[4]; } my_test; my_test.i = 0x01020304; // cosa stampa la seguente linea? printf("s[0]=%d s[1]=%d s[2]=%d s[3]=%d\n", my_test.s[0], my_test.s[1], my_test.s[2], my_test.s[3]); }
ho inizializzato il campo i e vado a leggere il campo s: ma allora la printf() stampa valori indefiniti!
No, lui si ricordava che "le union allocano memoria per la più grande delle variabili interne, variabili che condividono lo stesso spazio di memoria", quindi non cadde nel tranello, e rispose quasi perfettamente... quasi, perché cadde nel 2º livello di errore, quello che ti porta a dire:
ho inizializzato i, però leggo s, che è come se fosse stata inizializzata anche lei, quindi la riposta è: s[0]=1 s[1]=2 s[2]=3 s[3]=4 !
Ok, quasi giusto: in realtà la risposta è:
s[0]=4 s[1]=3 s[2]=2 s[3]=1
Il nostro amico A.A. se ne rese conto tornando a casa, quando l'errore ormai era fatto: nella locazione s[0] ci finisce la parte meno significativa di i (quindi 0x04), e così via gli altri numeri, per cui il risultato era in ordine inverso. Va beh, cose che succedono...
Se cercate in rete con google troverete tanti utili esempi d'uso delle union, tra i quali, direi, i più interessanti sono quelli per il trattamento di dati con contenuto variabile (protocolli di comunicazione, per esempio) in cui si vuole trattare, con la stessa struttura dati, informazioni di tipo diverso, e interpretando la union, di volta in volta, nella maniera corretta selezionando un opportuno flag mantenuto dal programma. Questo permette di fare programmi flessibili e risparmiosi di memoria (rispetto all'uso delle struct), cosa che in alcuni ambienti di sviluppo potrebbe risultare utile.
Occhio però: per la maniera stessa in cui funzionano le union sono flessibili ma ingannevoli, e gli errori subdoli di funzionamento sono dietro l'angolo che aspettano. Bisogna essere molto rigorosi nel mantenere, e testare, il flag di stato che ci indica quale personalità della union stiamo usando in ogni momento.
Ciao e al prossimo post.
Questo post è ispirato ad una storia vera, ma ogni riferimento a fatti o persone realmente esistiti è puramente casuale (uhmm ???)
Nessun commento:
Posta un commento