Differenze tra le versioni di "Gestire con sicurezza le Strutture esterne"
Riga 10: | Riga 10: | ||
− | + | =Conoscere la dimensione di una ''Struttura'' da utilizzare= | |
− | Dunque, | + | Per ciascuna ''Struttura'' esterna da utilizzare, qualora nel codice essa non venga creata ed istanziata da alcuna funzione esterna e debba essere passata ad altra funzione esterna, sarà necessario conoscere la sua dimensione. Questo perché si dovrà creare la variabile di tipo ''Puntatore'' ad un'area di memoria riservata che andrà a sostituire la ''Struttura'' esterna, accogliendo quindi i dati che quella avrebbe normalmente ricevuto nei suoi membri. |
+ | |||
+ | Dunque, scriveremo nella libreria dinamica condivisa ''.so'', da noi scritta in linguaggio C, una funzione per ciascuna ''Struttura'' da utilizzare. Ciascuna funzione ritornerà la dimensione della ''Struttura'' medesima. In ordine al nome della ''Struttura'', da inserire nella predetta funzione C, si deve precisare che: | ||
====Caso in cui la ''Struttura'' è dichiarata nel file ''header'' con la parola chiave "''typedef''"==== | ====Caso in cui la ''Struttura'' è dichiarata nel file ''header'' con la parola chiave "''typedef''"==== | ||
In questo caso, se è dichiarata anche l'etichetta della ''Struttura'' ed il suo nome ''alias'' | In questo caso, se è dichiarata anche l'etichetta della ''Struttura'' ed il suo nome ''alias'' | ||
Riga 75: | Riga 77: | ||
− | + | =Leggere e scrivere nei membri delle ''Strutture''= | |
Per leggere e scrivere nei membri che ci interessano di una ''Struttura'', si porrano nella nostra libreria ''ad hoc'' una serie di funzioni, alle quali come loro argomento si passerà una variabile di tipo ''Puntatore'', avendo avuto l'accortezza nel codice Gambas di dimensionare oppurtunamente ed adeguatamente (ossia riservare un'area di memoria <SPAN style= "text-decoration:underline">di dimensione identica</span> a quella della Struttura da gestire) tale ''Puntatore'' mediante la funzione ''Alloc()'' nella modalità vista nel precedente paragrafo "''Conoscere la dimensione di una Struttura da utilizzare''". | Per leggere e scrivere nei membri che ci interessano di una ''Struttura'', si porrano nella nostra libreria ''ad hoc'' una serie di funzioni, alle quali come loro argomento si passerà una variabile di tipo ''Puntatore'', avendo avuto l'accortezza nel codice Gambas di dimensionare oppurtunamente ed adeguatamente (ossia riservare un'area di memoria <SPAN style= "text-decoration:underline">di dimensione identica</span> a quella della Struttura da gestire) tale ''Puntatore'' mediante la funzione ''Alloc()'' nella modalità vista nel precedente paragrafo "''Conoscere la dimensione di una Struttura da utilizzare''". | ||
<BR>Se, invece, vi è una funzione esterna della libreria esterna principale che inizializza (e quindi anche dimensionandola) nel codice Gambas la variabile di tipo ''Puntatore'' ad una ''Struttura'' in C, allora alla libreria ''ad hoc'' si passerà tale variabile ''Puntatore''. | <BR>Se, invece, vi è una funzione esterna della libreria esterna principale che inizializza (e quindi anche dimensionandola) nel codice Gambas la variabile di tipo ''Puntatore'' ad una ''Struttura'' in C, allora alla libreria ''ad hoc'' si passerà tale variabile ''Puntatore''. | ||
Riga 156: | Riga 158: | ||
− | + | =Gestione mediante l'uso del metodo ''GetExternSymbol()'' della Classe ''System'' di Gambas= | |
Una seconda possibilità, per gestire le risorse della nostra libreria esterna .so ''ad hoc'' (creata per poter utilizzare con ''sicurezza'' le ''Strutture'' in C presenti in uno o più file ''header'' della libreria esterna principale), è quella offerta dal metodo ''.GetExternSymbol()'' della Classe ''System''. | Una seconda possibilità, per gestire le risorse della nostra libreria esterna .so ''ad hoc'' (creata per poter utilizzare con ''sicurezza'' le ''Strutture'' in C presenti in uno o più file ''header'' della libreria esterna principale), è quella offerta dal metodo ''.GetExternSymbol()'' della Classe ''System''. | ||
Riga 282: | Riga 284: | ||
− | - relativamente all'uso del metodo ''System.GetExternSymbol()'' mostriamo un esempio | + | - relativamente all'uso del metodo ''System.GetExternSymbol()'' mostriamo un esempio |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | <FONT Color=red size=4><B>Paragrafo in costruzione</b></font> | ||
− | + | =Ottenere il ''Puntatore'' ad un membro di una ''Struttura'' esterna= | |
Mostriamo di seguito le modlità per ottenere il ''Puntatore'' ad un membro di una ''Struttura'' esterna, utile per una gestione successiva del medesimo. | Mostriamo di seguito le modlità per ottenere il ''Puntatore'' ad un membro di una ''Struttura'' esterna, utile per una gestione successiva del medesimo. | ||
Versione delle 07:53, 5 nov 2015
Talvolta nell'uso delle risorse appartenenti a librerie esterne ci si può imbattere in Strutture molto complesse, dichiarate nei relativi file header (.h), la trascrizione delle quali in Gambas può risultare assai difficile.
Per essere sicuri di non commettere errori, si può scegliere che alcune di queste Strutture, e comunque quelle più ostiche, non vengano ricostruite e dichiarate nel codice del progetto Gambas, ma usate così come sono in una speciale libreria esterna dinamica condivisa (.so) appositamente da noi realizzata.
Più in particolare per ogni struttura che si intende usare, all'interno di tale apposita libreria condivisa (.so) vengono scritte in C alcune funzioni che verranno richiamate dall'applicativo Gambas principale.
Una di queste funzioni deve ritornare la dimensione in byte della Struttura, così da poterla allocarla con Gambas mediante la creazione di una variabile di tipo Puntatore. Questa incombenza può essere omessa se ad inizializzare la variabile di tipo Puntatore è una funzione della libreria esterna principale, di cui intendiamo sfruttare le risorse.
Le altre funzioni servono a leggere e scrivere dentro la Struttura. Ad ogni funzione, atta a leggere o scrivere nella Struttura, si passerà la relativa variabile di tipo Puntatore, creata in Gambas - come già detto - all'atto dell'allocazione, e l'eventuale valore da scrivere (se si deve scrivere in un membro della Struttura).
Indice
Conoscere la dimensione di una Struttura da utilizzare
Per ciascuna Struttura esterna da utilizzare, qualora nel codice essa non venga creata ed istanziata da alcuna funzione esterna e debba essere passata ad altra funzione esterna, sarà necessario conoscere la sua dimensione. Questo perché si dovrà creare la variabile di tipo Puntatore ad un'area di memoria riservata che andrà a sostituire la Struttura esterna, accogliendo quindi i dati che quella avrebbe normalmente ricevuto nei suoi membri.
Dunque, scriveremo nella libreria dinamica condivisa .so, da noi scritta in linguaggio C, una funzione per ciascuna Struttura da utilizzare. Ciascuna funzione ritornerà la dimensione della Struttura medesima. In ordine al nome della Struttura, da inserire nella predetta funzione C, si deve precisare che:
Caso in cui la Struttura è dichiarata nel file header con la parola chiave "typedef"
In questo caso, se è dichiarata anche l'etichetta della Struttura ed il suo nome alias
typedef struct etichetta { ... ... ... } nome_alias;
oppure se è dichiarato soltanto il nome alias della Struttura:
typedef struct { ... ... ... } nome_alias;
allora come argomento della funzione sizeof() in C andrà indicato soltanto il nome alias della Struttura:
int nome_funzione() { return sizeof(nome_alias); }
Caso in cui la Struttura non è dichiarata con la parola chiave "typedef"
In questo caso:
- se è presente soltanto l'etichetta della Struttura
struct etichetta { ... ... ... };
allora come argomento della funzione sizeof() in C andrà indicata l'etichetta della Struttura preceduta dalla parola struct:
int nome_funzione() { return sizeof(struct etichetta); }
- se è presente il solo nome alias della Struttura
struct { ... ... ... } nome_alias;
allora come argomento della funzione sizeof() in C andrà indicato soltanto il nome alias della Struttura:
int nome_funzione() { return sizeof(nome_alias); }
- se sono presenti l'etichetta ed il nome alias della Struttura
struct etichetta { ... ... ... } nome_alias;
allora come argomento della funzione sizeof() in C andrà indicato soltanto il nome alias della Struttura:
int nome_funzione() { return sizeof(nome_alias); }
Come già detto, se vi è una funzione della libreria esterna principale che inizializza nel codice Gambas la variabile di tipo Puntatore, allora questa funzione C è inutile.
Se deve essere conosciuta la dimensione di un membro che punta ad una sub-Struttura, va ovviamente posta come argomento della funzione sizeof() il nome della sub-Struttura:
int nome_funzione() { return sizeof(nome_della_sub-Struttura); }
Leggere e scrivere nei membri delle Strutture
Per leggere e scrivere nei membri che ci interessano di una Struttura, si porrano nella nostra libreria ad hoc una serie di funzioni, alle quali come loro argomento si passerà una variabile di tipo Puntatore, avendo avuto l'accortezza nel codice Gambas di dimensionare oppurtunamente ed adeguatamente (ossia riservare un'area di memoria di dimensione identica a quella della Struttura da gestire) tale Puntatore mediante la funzione Alloc() nella modalità vista nel precedente paragrafo "Conoscere la dimensione di una Struttura da utilizzare".
Se, invece, vi è una funzione esterna della libreria esterna principale che inizializza (e quindi anche dimensionandola) nel codice Gambas la variabile di tipo Puntatore ad una Struttura in C, allora alla libreria ad hoc si passerà tale variabile Puntatore.
Lettura e scrittura
- Per scrivere in un membro:
void nome_funzione(nome_della_Struttura *p, int valore_da_scrivere) { p->nome_membro = valore_da_scrivere; }
- per leggere un membro, ad esempio per ritornare un valore Integer:
int nome_funzione(nome_della_Struttura *p) { return p->nome_membro; }
Per ritornare il valore di un membro di una sub-Struttura vettoriale contenuta nella Struttura principale, si tiene conto dell'indice della sub-Struttura vettoriale prescelta:
int nome_funzione(nome_della_Struttura *p) { return p->nome_sub_Struttura_vettoriale[numero_indice].nome_membro; }
- oppure per ritornare una Stringa:
char * nome_funzione(nome_della_Struttura *p) { return p->nome_membro; }
- oppure per ritornare un puntatore ad una Struttura secondaria contenuta in un'altra Struttura principale:
nome_Struttura_secondaria * nome_funzione(nome_della_Struttura_principale *p) { return &p->nome_membro_che_punta_alla_Struttura_secondaria; }
Anche in questo caso se la Struttura non è dichiarata con la parola chiave "typedef", allora il nome della Struttura andrà preceduto dalla paola struct, oppure union se si tratta di una Union:
union nome_della_union * nome_funzione(nome_della_Struttura_principale *p) { return &p->nome_membro_che_punta_alla_Union; }
Riferimento al file header della libreria esterna principale
Ovviamente in testa al codice della nostra libreria ad hoc, va posto il tag #include "fileheader.h" riferito al file header della libreria principale, della quale si intendono utilizzare le risorse nell'applicativo Gambas, ed alle quali - tutte o solo alcune - si fa riferimento nella nostra libreria ad hoc:
// In testa il riferimento al file header della libreria principale: #include "liberiaprincipale.h"
Applicazione in ausilio
Potremo anche creare dall'applicazione principale Gambas la nostra apposita libreria esterna dinamica condivisa:
Private Procedure Genera_Struttura() Dim st As New String[][] Dim percorso, s As String Dim b As Byte ' Vengono inseriti i membri della Struttura da gestire con sicurezza. ' Nella prima dimensione della matrice vanno inseriti la definizione della Struttura e la tipologia di ciascun suo membro nel rispetto della loro posizione all'interno della Struttura medesima. ' Nella seconda dimensione della matrice vengono inseriti gli identificatori di ciascun membro della Struttura in corrispondenza dei rispettivi tipi presenti negli elementi della prima dimensione. ' Riguardo al primo elemento di ciascuna delle due dimensioni bisognerà fare attenzione in particolare se nella Struttura è presente la parola chiave "typedef" e/o il nome alias. st.Add(["struct ", "char ", "short ", "int "]) st.Add(["STRUTTURA ", "c", "s", "i"]) ' Qui si inserisce la libreria esterna .h (il suo file "header"), nella quale è contenuta la Struttura da gestire con sicurezza: s = "#include <libreria_esterna.h>\n\n\n" ' Questa riga crea la funzione per ottenere la dimensione della Struttura da gestire con sicurezza: s &= "\nint Dim_" & st[1][0] & "() {\n return sizeof(" & st[0][0] & st[1][0] & ");\n}" ' Qui si creano le funzioni di lettura e di scrittura dei membri della Struttura da gestire con sicurezza: For b = 1 To st[0].Max s &= String$(4, "\n") & st[0][b] & "Legge_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p) {" & "\n return p->" & st[1][b] & ";\n}" s &= "\n\nvoid Scrive_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p, " & st[0][b] & "v) {" & "\n p->" & st[1][b] & " = v;\n}" Next ' Viene salvato il sorgente della Libreria dinamica .so ad hoc, da noi creata, per gestire con sicurezza la Struttura esterna: File.Save("/tmp/Libadhoc.c", s) ' Viene infine generata la Libreria dinamica .so ad hoc, da noi creata: Shell "gcc -o /tmp/Libadhoc.so /tmp/membri.c -shared" Wait End
Gestione mediante l'uso del metodo GetExternSymbol() della Classe System di Gambas
Una seconda possibilità, per gestire le risorse della nostra libreria esterna .so ad hoc (creata per poter utilizzare con sicurezza le Strutture in C presenti in uno o più file header della libreria esterna principale), è quella offerta dal metodo .GetExternSymbol() della Classe System.
Al riguardo possiamo adottare almeno due modalità.
Scrivere una funzione per ogni azione da esercitare su un membro
All'interno della libreria dinamica condivisa esterna, da noi creata, verrà scritta una o due funzioni (lettura e/o scrittura) da eseguire su un membro della Struttura esterna.
Vediamo un esempio pratico.
Poniamo il caso che la Struttura esterna da gestire, dichiarata nel file header della libreria esterna principale, sia la seguente:
struct STRUTTURA { short s; int i; }; struct STRUTTURA st;
e che intendiamo leggere e scrivere dati da/sul membro int i.
Dunque la libreria dinamica condivisa esterna ad hoc, che dovremo noi creare, sarà la seguente:
#include "/percorso/del/file.h" void Scrivi(struct STRUTTURA *p, int val) { p->i = val; } int Leggi(struct STRUTTURA *p) { return p->i; }
Il codice Gambas dell'applicazione sarà il seguente:
Library "/percorso/della/libreria/esterna/da/noi/creata" Private Extern Scrivi(po As Pointer, i As Integer) Private Extern Leggi(po As Pointer) As Integer Public Sub Main() Dim p As Pointer p = System.GetExternSymbol("/percorso/della/libreria/esterna/da/noi/creata", "st") Scrivi(p, 99) Print Leggi(p) End
Puntare a variabili Globali che si riferiscono ai membri della Struttura esterna
Questa modalità prevede il puntamento a variabili globali, alle quali vengono assegnati direttamente i valori contenuti dai rispettivi membri della Struttura esterna da gestire, oppure per scrivervi.
La nostra speciale libreria esterna .so sarà sostanzialmente così impostata:
// In testa il riferimento al file header della libreria principale: #include "liberiaprincipale.h" // Se non v'è necessità di puntare ai particolari membri delle Strutture in C, bensì soltanto ad esse, si dichiareranno come globali le variabili del tipo di quelle Strutture da utilizzare. // Quindi con il metodo System.GetExternSymbol() si richiameranno tali variabili globali delle Strutture': Struttura_Utilizzata variabile_struttura_1; // Se devono essere richiamate Strutture puntate all'interno dei membri di una Struttura principale, vanno qui dichiarate anche le variabili di tali Strutture 'secondarie' : Sub-Struttura_di_una_Struttura_Principale variabile_sub-struttura; // Si dichiareranno come globali le variabili del tipo dei particolari membri delle Strutture utilizzate, di cui si intende leggere il valore contenuto: char * c; // Contiene caratteri testuali int i; // Contiene un intero long l; // Contiene un long // Se, invece, è necessario leggere nei membri di una singola Struttura utilizzata, si utilizerà un'apposita Funzione: int funzione_lettura(Struttura_Utilizzata *variabile_struttura_2) { c = variabile_struttura_2->primo_membro; i = variabile_struttura_2->secondo_membro_che_punta_ad_un'altra_struttura(sub-struttura).membro_della_sub-struttura; l = variabile_struttura_2->terzo_membro; // Caso in cui si deve passare direttamente una sub-struttura presente come membro della Struttura principale: variabile_sub-struttura = variabile_struttura_2->membro_della_sub-struttura; return (0); }
Da precisare che i simboli, puntabili dal metodo System.GetExternSymbol() di Gambas, sono ovviamente le diverse variabili, purché poste come globali, nonché quelle poste come argomenti delle funzioni contenute dalla nostra libreria ad hoc.
Esempi pratici
Circa quanto esposto nei precedenti paragrafi del presente argomento:
- relativamente all'uso delle sole funzioni esterne mostriamo di seguito un codice semplicemente per conoscere la quantità di memoria occupata complessivamente da una Struttura (in questo esempio la Struttura "XGCValues" presente nel file header /X11/Xlib.h):
' Dichiariamo che la funzione esterna, che useremo, è presente nella libreria, da noi appositamente creata, "libadhoc.so": Library "/tmp/libadhoc" ' Dichiariamo la funzione esterna presente nella libreria, da noi appositamente creata, "libadhoc.so": Private Extern Dim_XGCValues() As Integer Public Sub Main() Dim i As Integer ' Scriviamo il codice in C per creare l'apposita libreria condivisa: File.Save("/tmp/libadhoc.c", "#include <X11/Xlib.h>\n" & "\nint Dim_XGCValues() {\n" & " return sizeof(XGCValues);\n}") ' Generiamo la nostra libreria condivisa "libadhoc.so": Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -shared -lX11" Wait ' Invochiamo la funzione esterna presente nella libreria condivisa "libadhoc.so", da noi appositamente creata, ' che ci dirà la quantità di memoria occupata dalla Struttura prescelta: i = Dim_XGCValues() ' Mostriamo il risultato: Print "La Struttura 'XGCValues' occupa "; i; " byte." End
nonché rinviamo a questa pagina della WIKI per esempi sulla scrittura di dati nei membri di una Struttura esterna in C.
- relativamente all'uso del metodo System.GetExternSymbol() mostriamo un esempio
Paragrafo in costruzione
Ottenere il Puntatore ad un membro di una Struttura esterna
Mostriamo di seguito le modlità per ottenere il Puntatore ad un membro di una Struttura esterna, utile per una gestione successiva del medesimo.
Modalità conoscendo la dimensione di una Struttura da utilizzare
Mostriamo un semplice esempio, nel quale abbiamo una semplice libreria esterna, che chiameremo "LibreriaEsempio.c", il cui codice C è il seguente:
struct STRUTTURA { int i; short s; char c; long l; } stru; int Dim_Stru() { return sizeof(stru); } void* Ottiene_PuntMembro(struct STRUTTURA * p) { return &p->c; } int Legge_StruChar(struct STRUTTURA * p) { return p->c; }
Il codice sorgente di detta libreria condivisa sarà posto nella cartella Dati del nostro progetto.
Il codice principale di Gambas sarà:
Library "/tmp/LibreriaEsempio" Private Extern Dim_Stru() As Integer Private Extern Ottiene_PuntMembro(po As Pointer) As Pointer Private Extern Legge_StruChar(poC As Pointer) As Integer Public Sub Main() Dim p, puntatore_membro As Pointer Dim st As Stream Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait p = Alloc(Dim_Stru()) puntatore_membro = Ottiene_PuntMembro(p) ' Scriviamo per verifica: st = Memory puntatore_membro For Read Write Write #st, 66 As Byte st.Close ' Leggiamo per verifica: Print Legge_StruChar(p) Free(p) End
Modalità con System.GetExternSymbol()
Anche in quest'altro caso abbiamo una semplice libreria esterna, che chiameremo "LibreriaEsempio.c", il cui codice C è il seguente:
struct STRUTTURA { int i; short s; char c; long l; } stru; void* Ottiene_PuntMembro(struct STRUTTURA * p) { return &p->c; } int Legge_StruChar(struct STRUTTURA * p) { return p->c; }
Il codice sorgente di detta libreria condivisa sarà posto nella cartella Dati del nostro progetto.
Il codice principale di Gambas sarà:
Library "/tmp/LibreriaEsempio" Private Extern Ottiene_PuntMembro(po As Pointer) As Pointer Private Extern Legge_StruChar(poC As Pointer) As Integer Public Sub Main() Dim p, puntatore_membro As Pointer Dim st As Stream Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait p = System.GetExternSymbol("/tmp/LibreriaEsempio", "stru") puntatore_membro = Ottiene_PuntMembro(p) ' Scriviamo per verifica: st = Memory puntatore_membro For Read Write Write #st, 66 As Byte st.Close ' Leggiamo per verifica: Print Legge_StruChar(p) End