La struttura dati Union in C# ? Si può…

Tutti coloro che sviluppano in C/C++ si trovano molto spesso ad utilizzare una particolare struttura dati che in molti casi permette un notevole risparmio di memoria, in quanto ci fornisce la possibilità di utilizzare la stessa area per salvare in momenti diversi, valori di tipo diverso.

Ovviamente sto parlando della union, tipo sconosciuto a chi sviluppa da sempre solo ed esclusivamente in C#.

A questa mancanza, si può però ovviare utilizzando due strumenti che il C# ed il .Net Framework ci forniscono :

  • Il tipo struct;
  • L’attributo StructLayout (nel namespace System.Runtime.InteropServices);

In che modo ?

L’attributo StructLayout, permette di definire la modalità con cui il CLR disporrà in memoria i campi che costituiscono una classe oppure una struct. I valori ammessi da questo attributo sono i seguenti :

  • Auto : è il CLR a decidere come disporre i valori dei campi in memoria, non rispettando necessariamente l’ordine di dichiarazione degli stessi. Questa opzione è molto utile, in quanto permette di risparmiare, da parte del CLR, l’utilizzo dei byte di padding che servono a fare in modo che i campi siano allineati a 1,4 oppure 8 byte in base all’architettura del sistema. Una non perfetta distribuzione dei campi in memoria può implicare una dimensione complessiva maggiore del dato rispetto a quella strettamente necessaria. L’opzione Auto è quella predefinita per le classi;
  • Sequential : i valori vengono predisposti in memoria in maniera sequenziale secondo l’ordine di dichiarazione. In questo caso, si corre ovviamente il rischio dell’aggiunta di byte di padding inseriti ad hoc dal CLR, se non abbiamo dichiarato secondo una opportuna sequenza i campi. Questo è il valore predefinito per le struct;
  • Explicit : è possibile esplicitare la posizione/offeset dei campi rispetto all’indirizzo di partenza della classe o struttura, utilizzando l’ulteriore attributo FieldOffset da applicare a ciascun campo. Sarà questo valore che ci verrà in aiuto per la dichiarazione di una union;

La dichiarazione di una union, possiamo immaginarla nel modo seguente :

[StructLayout(LayoutKind.Explicit)]
public struct MyUnion
{
	[FieldOffset(0)]
	public byte byteValue;
	[FieldOffset(0)]
	public int intValue;
	[FieldOffset(0)]
	public short shortValue;
}
Come possiamo osservare, è stato specificato che rispetto all’indirizzo di partenza di allocazione della struct, tutti i campi hanno offeset pari a zero. Ciò vuol dire che si sovrapporranno l’uno con l’altro.
Eseguiamo ad esempio il seguente frammento di codice :
MyUnion myUnion = new MyUnion();
myUnion.byteValue = 5;
myUnion.intValue = 1234567890;
myUnion.shortValue = 9876;

int size = Marshal.SizeOf(myUnion);

Dopo l’esecuzione dell’istruzione 2, osserviamo che l’area di memoria allocata per la struct appare nel modo seguente :

3618.union_mem_1_thumb_0A0251AB

Dove si può osservare il valore 5 all’indirizzo di partenza, assegnato al campo byteValue. A seguito dell’istruzione 3, invece, troviamo la seguente condizione :

6747.union_mem_2_2944F87E
Il valore 5 è stato sovrascritto dalla rappresentazione binaria del numero intero 1234567890 che abbiamo assegnato al campo intValue. Infine, eseguendo l’istruzione 4, abbiamo :

4152.union_mem_3_11CA444D

Dove si evince la presenza della rappresentazione binaria del valore 9876 assegnato al campo shortValue.

Nell’ultima istruzione, viene calcolata la dimensione della struttura dati che stiamo utilizzando e come possiamo osservare dalla figura seguente, essa è 4 byte.

4617.union_mem_4_24329502

Tale dimensione è ovviamente determinata dal tipo di dato più grande che abbiamo dichiarato nella struct, ossia l’int (alias C# per il tipo Int32 del CLS) che occupa appunto 4 byte e non dalla somma delle dimensioni dei campi dichiarati nella struct (1 + 4 + 2 = 7).

Ciò che abbiamo ottenuto è a tutti gli effetti una union…in C# !!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s