Differenze tra le versioni di "Gestire con un Puntatore le Strutture esterne"

Da Gambas-it.org - Wikipedia.
Riga 34: Riga 34:
 
Ora verifichiamo il nuovo indice: 4. Questo numero corrisponde esattamente con il valore della dimensione di un Intero (''int''). Quindi il primo byte del valore assegnato a tale Intero sarà posto al byte di indice 4 (dunque al 5° byte), e occuperà ovviamente ben 4 byte, spostando così il puntatore interno al byte di indice 8 dell'area di memoria della ''Struttura'' esterna.
 
Ora verifichiamo il nuovo indice: 4. Questo numero corrisponde esattamente con il valore della dimensione di un Intero (''int''). Quindi il primo byte del valore assegnato a tale Intero sarà posto al byte di indice 4 (dunque al 5° byte), e occuperà ovviamente ben 4 byte, spostando così il puntatore interno al byte di indice 8 dell'area di memoria della ''Struttura'' esterna.
  
* Possiamo passare a individuare il terzo membro, che essendo una variabile ''Puntatore'' (''char *'') occupa 8 byte. Dobbiamo, quindi, verificare se l'attuale numero dell'indice, al quale ci siamo sin'oraspostati, corrisponde ad 8 o ad un multiplo di 8 (8, 16, 24, 32, etc).
+
* Possiamo passare ad individuare il terzo membro, che essendo una variabile ''Puntatore'' (''char *'') occupa 8 byte. Dobbiamo, quindi, verificare se l'attuale numero dell'indice, al quale ci siamo sin'ora spostati, corrisponde a 8 o ad un multiplo di 8 (8, 16, 24, 32, etc).
 
Abbiamo che l'indice attuale è 8 (9° byte dell'area di memoria della ''Struttura'' esterna) che corrisponde esattamente con il valore della dimensione di un ''Puntatore''. Pertanto il primo byte del valore contenuto dalla variabile Puntatore ''char *'' (ossia l'indirizzo di memoria puntata da questa variabile di tipo ''Puntatore'') è posto al byte di indice 8 (9° byte), ed occuperà in totale ben 8 byte, spostando così il puntatore interno al byte di indice 16 dell'area di memoria della ''Struttura'' esterna.
 
Abbiamo che l'indice attuale è 8 (9° byte dell'area di memoria della ''Struttura'' esterna) che corrisponde esattamente con il valore della dimensione di un ''Puntatore''. Pertanto il primo byte del valore contenuto dalla variabile Puntatore ''char *'' (ossia l'indirizzo di memoria puntata da questa variabile di tipo ''Puntatore'') è posto al byte di indice 8 (9° byte), ed occuperà in totale ben 8 byte, spostando così il puntatore interno al byte di indice 16 dell'area di memoria della ''Struttura'' esterna.
  
<TABLE>
+
* Possiamo passare ad individuare il quarto membro, che essendo una variabile ''Short'' (''short'') occupa 2 byte. Dobbiamo, quindi, verificare se l'attuale numero dell'indice, al quale ci siamo sin'ora spostati, corrisponde a 2 o ad un multiplo di 8 (4, 6, 8, 10, 12, 14, 16, etc).
<TR><TD align="center">indice</td><TD></td></tr>
+
Abbiamo che l'indice attuale è 16 (17° byte dell'area di memoria della ''Struttura'' esterna) che corrisponde ad un ''multiplo'' del valore della dimensione di uno ''short''. Pertanto il primo byte del valore contenuto dalla variabile ''short'' è posto al byte di indice 16 (17° byte), ed occuperà in totale ben 2 byte.
<TR><TD align="center">0</td><TD></td></tr>
 
<TR><TD align="center">0</td><TD></td></tr>
 
</table>
 
  
 +
La dimensione totale della ''Struttura'' raggiungerà il valore più prossimo pari ad un multiplo di 8. In tal caso: 24. Quindi la ''Struttura'' "in quanto tale" occuperà complessivamente 24 byte di memoria.
  
  
 +
====Esempio pratico====
 +
Mostriamo di seguito un esempio pratico, ove abbiamo una libreria dinamica condivisa .so esterna, il cui sorgente, scritto in linguaggio C, è il seguente:
 +
#include <stdlib.h>
 +
 +
 +
struct AAA {
 +
  char c;
 +
  short s;
 +
  int i;
 +
  char * p[5];
 +
  char * p1, *p2;
 +
  int n;
 +
};
 +
 +
struct AAA a;
 +
 +
 +
struct AAA * Estrae_Valori() {
 +
 +
  a.c = 0x0F;
 +
  a.s = 0x0400;
 +
  a.i = 0x00444444;
 +
 +
  a.p[0] = (char *) malloc(4);
 +
  a.p[1] = (char *) malloc(4);
 +
  a.p[2] = (char *) malloc(4);
 +
  a.p[3] = (char *) malloc(4);
 +
  a.p[4] = (char *) malloc(4);
 +
 +
  a.p[0][0] = 0x01;
 +
  a.p[0][1] = 0x02;
 +
  a.p[0][2] = 0x03;
 +
  a.p[0][3] = 0x04;
 +
 +
  a.p[1][0] = 11;
 +
  a.p[1][1] = 11;
 +
  a.p[1][2] = 11;
 +
  a.p[1][3] = 11;
 +
 
 +
  a.p[2][0] = 22;
 +
  a.p[2][1] = 22;
 +
  a.p[2][2] = 22;
 +
  a.p[2][3] = 22;
 +
 
 +
  a.p[3][0] = 33;
 +
  a.p[3][1] = 33;
 +
  a.p[3][2] = 33;
 +
  a.p[3][3] = 33;
 +
 
 +
  a.p[4][0] = 44;
 +
  a.p[4][1] = 44;
 +
  a.p[4][2] = 44;
 +
  a.p[4][3] = 44;
 +
 +
  a.p1 = (char *) malloc(4);
 +
  a.p1[0] = 99;
 +
  a.p1[1] = 99;
 +
  a.p1[2] = 99;
 +
  a.p1[3] = 99;
 +
 
 +
  a.p2 = "efgh";
 +
 
 +
  a.n = 10000;
 +
 
 +
  return &a;
 +
 +
}
 +
che ritorna alla funzione chiamante di Gambas l'indirizzo di memoria della sua ''Struttura''.
 +
 +
 +
Nel codice Gambas, che segue, si andrà a leggere da un ''Puntatore'', che ha raccolto l'indirizzo di memoria della ''Struttura'' esterna ritornata dalla libreria esterna, e con i ''Memory Stream'' i valori dei vari membri della predetta ''Struttura'':
 +
Private Extern Estrae_Valori() As Pointer In "/tmp/stru"
 +
 +
 +
'''Public''' Sub Main()
 +
 +
  Dim p1, po, p2, p3 As Pointer
 +
  Dim st, re As Stream
 +
 
 +
 +
<FONT Color=gray>' ''Generiamo la libreria esterna, scritta in C, contenente la "Struttura":''</font>
 +
  Shell "gcc -o /tmp/stru.so " & Application.Path &/ "stru.c -shared -fPIC" Wait
 +
 +
  p = Estrae_Valori()
 +
 +
  st = Memory p For Read
 +
 
 +
  Print Read #st As Byte  <FONT Color=gray>' ''Legge il 1° membro (char) che occupa 1 byte''</font>
 +
 +
  Seek #st, 2              <FONT Color=gray>' ''Ci spostiamo nel rispetto dell'allineamento dei membri''</font>
 +
  Print Read #st As Short    <FONT Color=gray>' ''Legge il 2° membro (short) che occupa 2 byte''</font>
 +
 +
  Print Read #st As Integer  <FONT Color=gray>' ''Legge il 3° membro (int) che occupa 4 byte''</font>
 +
 +
 +
  Read #st, po                <FONT Color=gray>' ''Legge il puntatore della prima dimensione di char * p[2]''</font>
 +
 
 +
    re = Memory po For Read  <FONT Color=gray>' ''Andiamo a dereferenziare il "Puntatore" per leggere nell'area di memoria da esso puntata''</font>
 +
    For b = 0 To 3
 +
      Read #re, j
 +
      Print b, j
 +
    Next
 +
    Seek #re, 32                            <FONT Color=gray>' ''Per ciascuna dimensione si salta di 32 byte avanti''</font>
 +
    For b = Seek(re) To Seek(re) + 3
 +
      Read #re, j
 +
      Print b, j
 +
    Next
 +
    Seek #re, 64                            <FONT Color=gray>' ''Per ciascuna dimensione si salta di 32 byte avanti''</font>
 +
    For b = Seek(re) To Seek(re) + 3
 +
      Read #re, j
 +
      Print b, j
 +
    Next
 +
    Seek #re, 96                            <FONT Color=gray>' ''Per ciascuna dimensione si salta di 32 byte avanti''</font>
 +
    For b = Seek(re) To Seek(re) + 3
 +
      Read #re, j
 +
      Print b, j
 +
    Next
 +
    Seek #re, 128                            <FONT Color=gray>' ''Per ciascuna dimensione si salta di 32 byte avanti''</font>
 +
    For b = Seek(re) To Seek(re) + 3
 +
      Read #re, j
 +
      Print b, j
 +
    Next
 +
 +
    re.Close
 +
   
 +
  Seek #st, Seek(st) + ((SizeOf(gb.Pointer) * 4))  <FONT Color=gray>' ''Si moltiplica per l'indice massimo di char * p[n]''</font>
 +
  Read #st, p2
 +
  s2 = Memory p2 For Read                    <FONT Color=gray>' ''Andiamo a dereferenziare il "Puntatore" per leggere nell'area di memoria da esso puntata''</font>
 +
    For b = 0 To 3
 +
      Read #s2, j
 +
      Print b, j
 +
    Next
 +
  s2.Close
 +
   
 +
  Read #st, p3
 +
  s3 = Memory p3 For Read                    <FONT Color=gray>' ''Andiamo a dereferenziare il "Puntatore" per leggere nell'area di memoria da esso puntata''</font>
 +
    Read #s3, t
 +
    Print t
 +
  s3.Close
 +
 
 +
  Print Read #st As Integer  <FONT Color=gray>' ''Legge il 7° membro (int) che occupa 4 byte''</font>
 +
 +
  st.Close
 +
 +
 +
'''End'''
  
  
  
 
<B><FONT Color=#FF0000 size=4>Pagina in costruzione</font></b>
 
<B><FONT Color=#FF0000 size=4>Pagina in costruzione</font></b>

Versione delle 10:07, 15 mag 2015

Come descritto anche in questa pagina, dedicata alla gestione in modo sicuro delle Strutture esterne, la lettura e la scrittura effettuate su Strutture esterne di una certa complessità è sempre molto difficile. Tanto è che, nella pagina segnalata nel collegamento, si è proposto nei casi più difficili di creare un'apposita libreria dinamica .so esterna scritta in C, nella quale gestire con le risorse del linguaggio C i membri di tali Strutture molto complesse sia in lettura che in scrittura.

La difficoltà della gestione delle Strutture molto complesse, appartenenti a librerie condivise .so esterne, consiste nel fatto che, tentando di riprodurre nel progetto Gambas tali Strutture, il linguaggio non riesce sempre a gestire la coerenza dei necessari allineamenti tra alcuni particolari membri costituenti la Struttura medesima.

Ad ogni modo alcune Strutture complesse possono essere affrontate tentandone la lettura e la scrittura attraverso un Puntatore, all'interno dell'area da esso puntata si scorrerà con i Memory Stream (per la lettura e/o scrittura), oppure semplicemente sommando o sottrando valori alla variabile Puntatore e dereferenziando con le apposite funzioni di dereferenziazione di un Puntatore previste da Gambas (solo per la lettura).

L'ostacolo maggiore è rappresentato dagli eventuali necessari allineamenti fra i membri, dei quali si dovrà tenere rigidamente conto durante la lettura e la scrittura nello spostamento lungo l'area puntata dal Puntatore.

In particolare, sorvolando sull'ovvia circostanza che i valori del primo membro della Struttura esterna sono leggibili e scrivibili a cominciare dal primo byte dell'area puntata dal Puntatore, v'è da precisare che per i valori appartenenti ai membri successivi al primo membro, il primo byte del valore di ogni membro (successivo al primo in assoluto della Struttura) si trova al numero di indice uguale al valore che rappresenta la dimensione (quantità di byte occupati) del tipo di variabile contenente il valore medesimo, oppure uguale al multiplo più prossimo al valore della dimensione predetta.

Cerchiamo di spiegare meglio qquanto detto con un esempio.
Poniamo il caso che la Struttura presente nella libreria condivisa dinamica esterna sia così composta:

struct STRUTTURA
  char c;
  int i;
  char * p;
  short s;
};

Laddove sostanzialmente abbiamo:
il primo membro di tipo char occupa 1 byte di memoria (come in Gambas il tipo Byte);
il secondo membro di tipo int occupa 4 byte di memoria (come in Gambas il tipo Integer);
il terzo membro di tipo char * (Puntatore) occupa 8 byte di memoria (come in Gambas il tipo Pointer);
il terzo membro di tipo short occupa 2 byte di memoria (come in Gambas il tipo Short).

Tali membri sono dislocati all'interno dell'area di memoria occupata dalla loro Struttura secondi il seguente ragionamento e calcolo:

  • il valore contenuto dal primo membro, ovviamente, ha inizio nell'area di memoria dal byte di indice 0 (il primo membro coincide sempre con l'indice zero).

Il primo membro occupa, come abbiamo visto solo un byte di memoria nell'area riservata, pertanto il prossimo byte da verificare è quello di indice 1.

  • Il secondo membro, però, essendo un Intero (int) ha una dimensione di 4 byte (occupa, cioè, 4 byte di memoria per rappresentare il valore assegnatogli). Pertanto, si dovrà verificare se il numero dell'indice da verificare (abbiamo visto che ora è uguale a 1) coincide con il valore della dimensione del tipo int, oppure con un suo multiplo (8, 12, 16, 20, etc). Notiamo che 1 (l'indice attuale) non coincide con il 4 (dimensione di memoria occupata dal tipo int) né con un suo multiplo. Pertanto, sposteremo in avanti l'indice di un altro byte per la verifica. L'indice 1 resterà con valore zero ed entrando così a far parte dell'allineamento.

Ora verifichiamo il nuovo indice: 2, che come il precedente non corrisponde al numero 4 (ricordiamo che v'è da piazzare un Intero !) né ad un multiplo di 4. Quindi spostiamo ancora in avanti il puntatore interno dell'indice (offset), come fatto appena prima, e lasceremo a zero anche il terzo byte (ossia quello di indice 2 !), entrando così anch'esso a far parte dell'allineamento.

Ora verifichiamo il nuovo indice: 3, che come il precedente non corrisponde al numero 4 (ricordiamo che v'è da piazzare un Intero !) né ad un multiplo di 4. Quindi spostiamo ancora in avanti il puntatore interno dell'indice, e lasceremo a zero anche il quarto byte (ossia quello di indice 3), entrando così anch'esso a far parte dell'allineamento.

Ora verifichiamo il nuovo indice: 4. Questo numero corrisponde esattamente con il valore della dimensione di un Intero (int). Quindi il primo byte del valore assegnato a tale Intero sarà posto al byte di indice 4 (dunque al 5° byte), e occuperà ovviamente ben 4 byte, spostando così il puntatore interno al byte di indice 8 dell'area di memoria della Struttura esterna.

  • Possiamo passare ad individuare il terzo membro, che essendo una variabile Puntatore (char *) occupa 8 byte. Dobbiamo, quindi, verificare se l'attuale numero dell'indice, al quale ci siamo sin'ora spostati, corrisponde a 8 o ad un multiplo di 8 (8, 16, 24, 32, etc).

Abbiamo che l'indice attuale è 8 (9° byte dell'area di memoria della Struttura esterna) che corrisponde esattamente con il valore della dimensione di un Puntatore. Pertanto il primo byte del valore contenuto dalla variabile Puntatore char * (ossia l'indirizzo di memoria puntata da questa variabile di tipo Puntatore) è posto al byte di indice 8 (9° byte), ed occuperà in totale ben 8 byte, spostando così il puntatore interno al byte di indice 16 dell'area di memoria della Struttura esterna.

  • Possiamo passare ad individuare il quarto membro, che essendo una variabile Short (short) occupa 2 byte. Dobbiamo, quindi, verificare se l'attuale numero dell'indice, al quale ci siamo sin'ora spostati, corrisponde a 2 o ad un multiplo di 8 (4, 6, 8, 10, 12, 14, 16, etc).

Abbiamo che l'indice attuale è 16 (17° byte dell'area di memoria della Struttura esterna) che corrisponde ad un multiplo del valore della dimensione di uno short. Pertanto il primo byte del valore contenuto dalla variabile short è posto al byte di indice 16 (17° byte), ed occuperà in totale ben 2 byte.

La dimensione totale della Struttura raggiungerà il valore più prossimo pari ad un multiplo di 8. In tal caso: 24. Quindi la Struttura "in quanto tale" occuperà complessivamente 24 byte di memoria.


Esempio pratico

Mostriamo di seguito un esempio pratico, ove abbiamo una libreria dinamica condivisa .so esterna, il cui sorgente, scritto in linguaggio C, è il seguente:

#include <stdlib.h>


struct AAA {
  char c;
  short s;
  int i;
  char * p[5];
  char * p1, *p2;
  int n;
};

struct AAA a;


struct AAA * Estrae_Valori() {

  a.c = 0x0F;
  a.s = 0x0400;
  a.i = 0x00444444;

  a.p[0] = (char *) malloc(4);
  a.p[1] = (char *) malloc(4);
  a.p[2] = (char *) malloc(4);
  a.p[3] = (char *) malloc(4);
  a.p[4] = (char *) malloc(4);

  a.p[0][0] = 0x01;
  a.p[0][1] = 0x02;
  a.p[0][2] = 0x03;
  a.p[0][3] = 0x04;

  a.p[1][0] = 11;
  a.p[1][1] = 11;
  a.p[1][2] = 11;
  a.p[1][3] = 11;
  
  a.p[2][0] = 22;
  a.p[2][1] = 22;
  a.p[2][2] = 22;
  a.p[2][3] = 22;
 
  a.p[3][0] = 33;
  a.p[3][1] = 33;
  a.p[3][2] = 33;
  a.p[3][3] = 33;
 
  a.p[4][0] = 44;
  a.p[4][1] = 44;
  a.p[4][2] = 44;
  a.p[4][3] = 44;

  a.p1 = (char *) malloc(4);
  a.p1[0] = 99;
  a.p1[1] = 99;
  a.p1[2] = 99;
  a.p1[3] = 99;
 
  a.p2 = "efgh";
 
  a.n = 10000;
  
  return &a;

}

che ritorna alla funzione chiamante di Gambas l'indirizzo di memoria della sua Struttura.


Nel codice Gambas, che segue, si andrà a leggere da un Puntatore, che ha raccolto l'indirizzo di memoria della Struttura esterna ritornata dalla libreria esterna, e con i Memory Stream i valori dei vari membri della predetta Struttura:

Private Extern Estrae_Valori() As Pointer In "/tmp/stru"


Public Sub Main()

 Dim p1, po, p2, p3 As Pointer
 Dim st, re As Stream
 

' Generiamo la libreria esterna, scritta in C, contenente la "Struttura":
  Shell "gcc -o /tmp/stru.so " & Application.Path &/ "stru.c -shared -fPIC" Wait

  p = Estrae_Valori()

  st = Memory p For Read
 
  Print Read #st As Byte   ' Legge il 1° membro (char) che occupa 1 byte

  Seek #st, 2              ' Ci spostiamo nel rispetto dell'allineamento dei membri
  Print Read #st As Short    ' Legge il 2° membro (short) che occupa 2 byte

  Print Read #st As Integer   ' Legge il 3° membro (int) che occupa 4 byte


  Read #st, po                ' Legge il puntatore della prima dimensione di char * p[2]
  
    re = Memory po For Read   ' Andiamo a dereferenziare il "Puntatore" per leggere nell'area di memoria da esso puntata
    For b = 0 To 3
      Read #re, j
      Print b, j
    Next
    Seek #re, 32                            ' Per ciascuna dimensione si salta di 32 byte avanti
    For b = Seek(re) To Seek(re) + 3
      Read #re, j
      Print b, j
    Next
    Seek #re, 64                            ' Per ciascuna dimensione si salta di 32 byte avanti
    For b = Seek(re) To Seek(re) + 3
      Read #re, j
      Print b, j
    Next
    Seek #re, 96                            ' Per ciascuna dimensione si salta di 32 byte avanti
    For b = Seek(re) To Seek(re) + 3
      Read #re, j
      Print b, j
    Next
    Seek #re, 128                            ' Per ciascuna dimensione si salta di 32 byte avanti
    For b = Seek(re) To Seek(re) + 3
      Read #re, j
      Print b, j
    Next

    re.Close
   
  Seek #st, Seek(st) + ((SizeOf(gb.Pointer) * 4))   ' Si moltiplica per l'indice massimo di char * p[n]
  Read #st, p2
  s2 = Memory p2 For Read                    ' Andiamo a dereferenziare il "Puntatore" per leggere nell'area di memoria da esso puntata
    For b = 0 To 3
      Read #s2, j
      Print b, j
    Next
  s2.Close
   
  Read #st, p3
  s3 = Memory p3 For Read                    ' Andiamo a dereferenziare il "Puntatore" per leggere nell'area di memoria da esso puntata
    Read #s3, t
    Print t
  s3.Close
 
  Print Read #st As Integer   ' Legge il 7° membro (int) che occupa 4 byte

  st.Close


End


Pagina in costruzione