Passare un'area riservata di memoria ad una funzione esterna

Da Gambas-it.org - Wikipedia.

Considereremo due casi: il caso in cui si debba passare ad una funzione semplicemente un'area allocata di memoria, affinché quella la riempi; ed il caso in cui, dopo aver allocato un'area di memoria, si debba riempirla, ed infine così passarla ad una funzione.

Passare semplicemente un'area allocata di memoria

Qualora una funzione esterna preveda che le si passi una Struttura, o comunque un'altra area allocata di memoria, per mezzo di un puntatore a quest'area riservata, affinché questa venga riempita dalla funzione medesima magari con due o più valori, che possono essere anche di tipo diverso; e che successivamente si debba procedere alla dereferenziazione, procederemo nel modo seguente:

1) allocheremo una sufficiente quantità di memoria, che sarà puntata da una variabile di tipo puntatore;

2) passeremo tale puntatore alla funzione esterna che provvederà a riempirla;

3) procederemo alla dereferenziazione. Se il valore restituito dalla funzione esterna è unico, ossia il suo indirizzo coincide con la struttura (o classe) stessa, e dunque o coincide con la parte iniziale dell'area, allora potranno essere utilizzate le consuete funzioni di dereferenziazione (Byte@(), Int@(), etc). Se invece I valori passati dalla funzione esterna sono più di uno, essi occuperanno in modo coerente con il tipo di valore, rappresentato da ciascuno, l'area di memoria da noi riservata e puntata dalla variabile puntatore, e andranno dereferenziati mediante l'uso dei Memory-Stream.


Vediamo un esempio astratto:

' Dichiariamo la funzione esterna dalla quale riceveremo il puntatore alla "Struttura" esterna:
Private Extern funzione_esterna(pnt As Pointer)


Public Sub Main()

 Dim p As Pointer
 Dim ms As Stream
 Dim by As Byte

' Ci riserviamo un'area sufficiente di memoria:
 p = Alloc(quantità_di_memoria_da_allocare)

' Passiamo alla funzione esterna il puntatore all'area allocata, affinché essa gli assegni il valore dell'indirizzo di memoria puntato:
 funzione_esterna(p)

' Andiamo a dereferenziare il pointer:
 ms = Memory p For Read
 
' Andiamo a leggere e mostrare in console i dati:
 For i = 0 To quantità_di_memoria_allocata - 1
    Read #ms, b
    Print b
 Next
 
' In fase di chiusura del programma, si procederà anche a "de-allocare", cioè a liberare, la porzione di memoria precedentemente allocata:
 Free(p)
 
End


Riempire un'area allocata di memoria e successivamente passarla ad una funzione

Talvolta il codice può richiedere di passare ad una funzione esterna un'area riservata di memoria debitamente riempita con tipi di valori che occupino ciascuno un ben determinato numero di byte all'interno di detta area riservata. Una volta riempita, come previsto, si passerà detta area riservata alla funzione esterna.
In Gambas 3 la procedura è complessa, nel senso che intervengono vari elementi e fasi. Nela prima fase si alloca un'area di memoria che sarà puntata da una variabile di tipo Puntatore. Per poter scrivere, o leggere, all'interno di quest'area riservata è necessario utilizzare una variabile di tipo Stream che punti a detta area riservata. Tale variabile di tipo Stream verrà generata mediante la funzione Memory Stream sulla base della già esistente variabile di tipo Puntatore, creata precedentemente all'atto dell'allocazione di un'area di memoria. Lo Stream è uno stratagemma, uno strumento di Gambas per lavorare con la memoria. Usando la variabile di tipo Stream non viene creata un'altra area di memoria, si usa comunque la stessa area dichiarata prima con la variabile di tipo puntatore. Lo Stream è soltanto un meccanismo per operare su quell'area là precedentemente allocata e puntata dalla variabile di tipo Puntatore. Quindi la variabile di tipo Stream va vista come una risorsa collaterale, che serve soltanto per scrivere o leggere i dati dentro la variabile di tipo Puntatore all'area allocata, ma che deve rimanere tutta interna a Gambas, e non deve essere passata alle funzioni esterne. Insomma, possiamo dire che solo Gambas sa che cosa sono le variabili Stream, ed alle funzioni esterne - appartenenti all'API di altri programmi e risorse - si devono passare soltanto dei Puntatori ad aree di memoria. Nel qual caso si posseggono sia l'area di memoria (allocata, esistente e preparata a dovere) sia la variabile di tipo Puntatore relativo (che deve puntare all'inizio).

Riepilogando, procederemo generalmente come segue:

1) si punterà all'area riservata di memoria con una variabile di tipo puntatore;
2) si genererà una variabile di tipo Stream dalla predetta variabile di tipo Puntatore mediante la funzione Memory Stream (For Write);
3) si riempirà l'area con valori del tipo coerente a quelli richesti;
4) si passerà, però, alla funzione comunque la variabile di tipo Puntatore (e non quella di tipo Stream !) che punta e rappresenta l'area di memoria allocata.


Come esempio pratico poniamo il caso di voler riportare in Gambas il seguente codice scritto in C, nel quale la funzione, alla quale deve essere passata l'area riservata di memoria, preveda come parametro, appunto, che venga passata una variabile di tipo puntatore che punta a quell'area riservata:

 unsigned char *data;

/* Viene allocata un'area di memoria */
 data = (unsigned char *)malloc(1024);

/* ...qui avviene il riempimento dell'area riservata con i valori prescritti */
  ......
  ......
  ......etc

/* Quindi viene passato alla funzione il puntatore all'area riempita */
  funz(data);

In Gambas avremo:

' Nel C era previsto un "Puntatore", in Gambas prevediamo egualmente e coerentemente un "Puntatore" per poter passare l'area allocata riempita !
Private Extern funzioneEsterna(param As Pointer)


Public Sub Main()

 Dim dati As Pointer
 Dim datStr As Stream
 Dim v1 As ...' tipo di valore in base a quello previsto nel codice C
 Dim v2 As ...' tipo di valore in base a quello previsto nel codice C
 ...etc...

 dati = Alloc(SizeOf(gb.Byte), 1024)
 
' Dal puntatore crea una variabile di tipo "Stream" in "scrittura":
 datStr = Memory dati For Write
 
' Scrive nella variabile di tipo Stream:
 Write #datStr, v1 As ...' tipo di valore in base a quello previsto nel codice C
 Write #datStr, v2 As ...' tipo di valore in base a quello previsto nel codice C
 ...etc...
 
' Passa infine alla funzione esterna comunque la variabile di tipo "Puntatore", precedentemente creata e che punta all'area riservata di memoria, ora riempita con i previsti valori:
 funzioneEsterna(dati)
 
 Free(dati)

End

Passare alla funzione esterna la proprietà ".Data" di un vettore

Se il parametro formale della variabile da passare richiede un Puntatore, una soluzione alternativa prevede che in Gambas si riempia di dati un vettore e si passi alla funzione esterna la Proprietà ".Data" del vettore medesimo:

funzioneEsterna(array.Data)