Scrivere una libreria esterna che ritorna una Struttura
Di seguito mostriamo alcuni esempi, nei quali la funzione esterna della libreria in C ritorna per "Valore" una Struttura.
Indice
Utilizzare nella funzione esterna una variabile del tipo della Struttura
1° esempio
Si può scrivere una libreria esterna condivisa ad hoc, contenente una funzione che ritorna una Struttura per "valore". Se la funzione esterna, scritta in C nel programma Gambas, prevede il ritorno al codice Gambas del semplice tipo della Struttura, la variabile del tipo della Struttura, usata nel codice scritto in C, dovrà essere dichiarata come globale.
Public Struct Nome_Struttura ' Dichiara una "Struttura" simile a quella dichiarata nel codice C a As Integer b As Pointer End Struct Private Extern prova() As Nome_Struttura In "/tmp/libprovaC" Public Sub Main() Dim nst As New Nome_Struttura Creaso() nst = prova() Print nst.a, String@(nst.b) End Private Procedure Creaso() File.Save("/tmp/libprovaC.c", "struct nome_struttura {\n" & " int a;\n" & " char *b;\n};\n\n" & "struct nome_struttura variabile_struttura;\n\n" & "struct nome_struttura *prova() {\n\n" & " variabile_struttura.a = 99; // Assegna i valori ai membri della Struttura\n" & " variabile_struttura.b = \"prova\";\n\n" & " return &variabile_struttura;\n\n}") Shell "gcc -o /tmp/libprovaC.so /tmp/libprovaC.c -shared -fPIC" Wait End
2° esempio
In quest'altro esempio nel codice Gambas dell'applicativo non è dichiarata ed usata una Struttura simile a quella dichiarata in C, ma si opererà sul Puntatore ottenuto, contenente l'indirizzo di memoria della Struttura del codice C, per estrarre i valori dei membri della Struttura.
Private Extern Prova() As Pointer In "/tmp/libreria_C" Public Sub Main() Dim p, po As Pointer Dim st, re As Stream Dim j, b As Byte Creaso() p = Prova() If p == 0 Then Error.Raise("Puntatore NULLO !") st = Memory p For Read Print Read #st As Integer ' Posizioniamo il puntatore interno del flusso al byte di indice 8 per gli effetti dell'allineamento, dato che il prossimo valore occupa 8 byte (è un "Puntatore"= 0, 8, 16, 24, 32, ...etc): Seek #st, 8 Read #st, po re = Memory po For Read For j = 0 To 3 Read #re, b Print Hex(b, 2) Next re.Close Print Read #st As Short st.Close End Private Procedure Creaso() File.Save("/tmp/libreria_C.c", "#include <stdlib.h>\n" & "struct AAA {\n" & " int i;\n" & " char * p;\n" & " short s;\n};\n\n" & "struct AAA a;\n\n" & "struct AAA * Prova() {\n\n" & " a.i = 444444;\n\n" & " a.p = (char *) malloc(4);\n" & " a.p[0] = 0x0A;\n" & " a.p[1] = 0x0B;\n" & " a.p[2] = 0x0C;\n" & " a.p[3] = 0x0D;\n\n" & " a.s = 0x0400;\n\n" & " return &a;\n\n}") Shell "gcc -o /tmp/libreria_C.so /tmp/libreria_C.c -shared -fPIC" Wait End
Caso in cui la funzione esterna ritorna una Struttura avente tra i suoi membri uno o più vettori di tipo "char"
Se un membro della Struttura, presente nella libreria esterna in C, è dichiarato come un vettore di tipo "char", allora il corrispondente membro della rispettiva Struttura in Gambas potrà essere dichiarato come vettore di tipo Byte[]. I valori di tale vettore di tipo Byte[] potranno essere recuperati, ai fini della ricomposizione dell'intera stringa di caratteri, con il metodo .ToString().
Public Struct Nome_Struttura b[4] As Byte a As Integer End Struct Private Extern prova() As Nome_Struttura In "/tmp/libprovaC" Public Sub Main() Dim nst As New Nome_Struttura Creaso() nst = prova() Print nst.b.ToString() Print nst.a End Private Procedure Creaso() File.Save("/tmp/libprovaC.c", "struct nome_struttura {\n" & " char b[4];\n" & " int a;\n};\n\n" & "struct nome_struttura variabile_struttura;\n\n" & "struct nome_struttura *prova() {\n\n" & " variabile_struttura.b[0] = 'p'; //assegna un carattere per ciascun elemento del vettore di tipo \"chr\"\n" & " variabile_struttura.b[1] = 'e';\n" & " variabile_struttura.b[2] = 'r';\n" & " variabile_struttura.b[3] = 'a';\n\n" & " variabile_struttura.a = 99;\n\n" & " return &variabile_struttura; // ritorna l'indirizzo di \"variabile_struttura\"\n\n};") Shell "gcc -o /tmp/libprovaC.so /tmp/libprovaC.c -shared -fPIC" Wait End
Utilizzare nella funzione esterna un Puntatore alla Struttura
Se la funzione utilizza e ritorna un Puntatore alla Struttura, allora detto Puntatore potrà essere dichiarato come locale.
Si potrà fare uso - come appoggio - di una variabile del tipo della Struttura, la quale permetterà al Puntatore di puntare alla sua area di memoria. In particolare al Puntatore alla Struttura si assegnerà l'indirizzo di memoria della variabile d'appoggio del tipo della Struttura.
Public Struct Struttura ' Dichiara una "Struttura" simile a quella dichiarata nel codice C a As Integer b As Pointer End Struct Private Extern prova() As Struttura In "/tmp/libprovaC" Public Sub Main() Dim st As New Struttura Creaso() st = prova() Print st.a, String@(st.b) End Private Procedure Creaso() File.Save("/tmp/libprovaC.c", "struct Nome_struttura {\n" & " int i;\n" & " char *c;\n};\n\n" & "struct Nome_struttura * prova() {\n\n" & " struct Nome_struttura st, *p;\n\n" & " p = &st;\n" & " p->i = 9999;\n" & " p->c = \"prova\";\n\n" & " return p;\n\n}") Shell "gcc -o /tmp/libprovaC.so /tmp/libprovaC.c -shared" Wait End
oppure (senza usare alcuna variabile d'appoggio) si assegnerà al Puntatore alla Struttura un'area di memoria allocat mediante la funzione "malloc()" della libreria standard di C:
Private Procedure Creaso() File.Save("/tmp/libprovaC.c", "#include <stdlib.h>\n\n" & "struct Nome_struttura {\n" & " int i;\n" & " char *c;\n};\n\n" & "struct Nome_struttura * prova() {\n\n" & " struct Nome_struttura *p = malloc(sizeof(struct Nome_struttura));\n\n" & " p->i = 9999;\n" & " p->c = \"prova\";\n\n" & " return p;\n\n}") Shell "gcc -o /tmp/libprovaC.so /tmp/libprovaC.c -shared" Wait End