Scrivere una libreria esterna che ritorna una Struttura

Da Gambas-it.org - Wikipedia.

Di seguito mostriamo alcuni esempi, nei quali la funzione esterna della libreria in C ritorna per "Valore" una Struttura.

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