Guida al Visual Basic .NET
Capitolo 91° - La classe Marshal e i puntatori
I puntatoriI puntatori sono speciali variabili che non contengono un valore, bensì un indirizzo ad un'altra area di memoria. I puntatori sono una caratteristica peculiare del C e dei suoi immediati discendenti e permettono di gestire la memoria a basso livello. Il .NET non supporta ufficialmente i puntatori, sebbene in C# sia possibile usarli in certi blocchi di codice non gestito. Nonostante ciò, è definito nel namespace System un tipo strutturato di nome IntPtr che rappresenta un puntatore, anche se molto diverso da quelli tipici del C. Nell'ambito di quest'ultimo linguaggio, infatti, si definisce un puntatore specificando a quali tipi di dato esso punti: un puntatore a Integer, significa, ad esempio, che l'area di memoria da esso puntata contiene un numero intero a 32 bit; allo stesso modo, un puntatore a Point indica che l'area di memoria puntata contiene una struttura di quel tipo, che viene rappresentata in binario come sequenza dei suoi membri, ossia due Int32 (X e Y). Questo consente di eseguire operazioni aritmetiche sui puntatori tenendo conto della dimensione occupata dai dati puntati. Non mi dilungo oltre nella spiegazione, pur interessante, poiché in .NET tutto questo non è possibile. Esiste solo IntPtr, che rappresenta un generico puntatore.La classe MarshalIl marshalling (da cui il nome della classe) consiste nel passare da dati gestiti a dati non gestiti e viceversa. Tipicamente, i "dati gestiti" sono le entità che noi utilizziamo nella programmazione ad oggetti: tipi value, strutture, oggetti, delegate, eccetera... Parallelamente, i "dati non gestiti" corrispondono alla rappresentazione grezza dei dati in memoria, ossia semplici sequenze di bytes. Per indicare dati non gestiti si utilizzano i puntatori, che riferiscono dove, nella memoria di lavoro, sono state allocate le informazioni che ci servono.Quando si lavora a basso livello sulla memoria, tuttavia, bisgna ricordarsi di eseguire sempre certe operazioni di cui normalmente non ci preoccupiamo, poiché vengono amministrate dal CLR e dal Garbage Collector:
Imports System.Runtime.InteropServices Module Module1 Sub Main() 'Un nuovo Guid. Il Guid è un tipo di identificativo 'usato in gran quantità dal Framework. 'È un tipo strutturato semplice del namespace 'System, perciò l'ho scelto come esempio Dim G As Guid = Guid.NewGuid() 'Calcola la dimensione in bytes di G Dim GuidSize As Int32 = Marshal.SizeOf(G) 'Un puntatore Dim Pointer As IntPtr 'La funzione AllocHGlobal (dove H sta per Handle) alloca 'un certo numero di bytes, passato come parametro, nella 'memoria di lavoro e restituisce un puntatore 'all'area allocata. In questo caso allochiamo un 'numero di bytes pari alla dimensione di G: Pointer = Marshal.AllocHGlobal(GuidSize) 'Copia la struttura G nell'area di memoria puntata 'da Pointer, eventualmente eliminando una vecchia 'struttura se esiste (True) Marshal.StructureToPtr(G, Pointer, True) 'Ora leggiamo un byte alla volta dall'area di memoria 'allocata, ed avremo la rappresentazione binaria 'della variabile G. 'La funzione ReadByte legge e restituisce un byte di 'informazione all'indirizzo puntato da Pointer. Come 'secondo parametro accetta un intero che indica l'offset 'di cui spostarsi rispetto all'indirizzo base For I As Int32 = 0 To GuidSize - 1 Console.Write("{0:X2} ", Marshal.ReadByte(Pointer, I)) Next 'Libera la memoria puntata da Pointer. Questa funzione 'è un po' più sofisticata, poiché 'non solo libera la memoria strettamente indicata da 'Pointer, ma elimina anche tutti i sottoriferimenti 'contenuti nella struttura. Ad esempio, se la struttura 'contenesse una stringa (che, come sappiamo è un 'tipo reference), la rappresentazione binaria 'indicherebbe solo un intero al posto della stringa, 'ossia un puntatore all'oggetto stringa che risiede 'in un'altra parte della memoria. DestroyStructure 'elimina anche riferimenti di questo tipo, assicurando 'che non rimanga alcuna area di memoria inutilizzata Marshal.DestroyStructure(Pointer, GetType(Guid)) Console.ReadKey() End Sub End ModuleGli altri metodi di Marshal hanno un utilizzo altamente specifico e molto tecnico, perciò non è utile analizzarli tutti. I membri più comuni sono stati esposti nell'esempio precedente, ed altre funzioni verrano trattate in seguito parlando di sicurezza.
C#, TypeScript, java, php, EcmaScript (JavaScript), Spring, Hibernate, React, SASS/LESS, jade, python, scikit, node.js, redux, postgres, keras, kubernetes, docker, hexo, etc...
|