Differenze tra le versioni di "Extern: richiamare funzioni esterne a Gambas"

Da Gambas-it.org - Wikipedia.
 
(173 versioni intermedie di 2 utenti non mostrate)
Riga 1: Riga 1:
Gambas consente di utilizzare potenzialità e capacità di sistemi esterni mediante il richiamo di loro funzioni. A volte infatti può capitare nella programmazione la necessità di utilizzare potenzialità che Gambas da solo non può offrire{[[#Note|1]]}. L'istruzione che Gambas pone a disposizione del programmatore per richiamare tali funzioni esterne è: '''Extern'''.
+
=Introduzione=
 +
Gambas consente di utilizzare potenzialità e capacità di sistemi (risorse) esterni implementandoli nel linguaggio attraverso i suoi ''[https://gambaswiki.org/wiki/comp?l=it Componenti]''.
 +
<BR>Gambas, però, non implementa tutte le migliaia di risorse informatiche disponibili, e talvolta può capitare nella programmazione la necessità di utilizzare funzionalità che la corrente versione di Gambas, essendone priva, non può direttamente offrire <SUP>&#091;[[#Note|nota 1]]&#093;</sup>; funzionalità che sono comunque espresse - come già detto - da sistemi esterni.
 +
<BR>Gambas consente di fruire di tali potenzialità esterne, ponendo disposizione del programmatore, per richiamare tali funzioni esterne, l'istruzione è: '''EXTERN'''.
  
 
Per il richiamo di funzioni esterne è necessario conoscere in particolare tre elementi:
 
Per il richiamo di funzioni esterne è necessario conoscere in particolare tre elementi:
Riga 6: Riga 9:
 
* la libreria nella quale è contenuta la funzione da richiamare.
 
* la libreria nella quale è contenuta la funzione da richiamare.
  
Se quel che si vuole ottenere è possibile solamente attraverso l'uso di una funzione esterna a Gambas, bisognerà individuare la specifica funzione che consente di realizzare il nostro obiettivo. La funzione esterna, utile allo scopo del programma, dovrà essere richiamata dal nostro programma Gambas. Poiché tale funzione esterna è scritta in C, bisognerà interpretare il significato e tradurla in forma comprensibile da Gambas. Inoltre, poiché essa è appunto ''esterna'' a Gambas, bisognerà conoscere il ''luogo'' ove essa si trova. Il ''luogo'' che contiene la funzione esterna è la "''Libreria''"; ed anzi una specifica libreria, la quale, pertanto, andrà dichiarata in anticipo rispetto alla funzione. Le librerie, contenenti funzioni ''esterne'' a Gambas, richiamabili da Gambas, sono quelle con estensione '''''.so''''' . E' opportuno, quando possibile, indicare anche il numero della versione della Libreria. Inoltre, se la libreria si trova in una cartella diversa da quella dedicata alle librerie (/lib/), sarà necessario specificare anche il percorso.
+
Se quel che si vuole ottenere è possibile solamente attraverso l'uso di una funzione esterna a Gambas, bisognerà individuare tale specifica funzione esterna che consente di realizzare il nostro obiettivo, e dichiararla nel nostro programma Gambas e esso richiamarla. Poiché tale funzione esterna è scritta in C, bisognerà interpretare il significato della sua dichiarazione originaria <SUP>&#091;[[#Note|nota 2]]&#093;</sup>, espressa in C, e tradurla in forma comprensibile a Gambas.
 +
<BR>Inoltre, poiché essa è appunto ''esterna'' a Gambas, bisognerà conoscere il ''luogo'' ove essa si trova. Il ''luogo'' che contiene la funzione esterna è la "''Libreria''"; ed anzi una specifica libreria, la quale, pertanto, andrà dichiarata in anticipo rispetto alla funzione. Le librerie, contenenti funzioni ''esterne'' a Gambas, richiamabili da Gambas, sono quelle con estensione '''''.so''''', ossia le "''Librerie condivise'' " <SUP>&#091;[[#Note|nota 3]]&#093;</sup>. E' opportuno, quando possibile, indicare anche il numero della versione della Libreria.
 +
<BR>Se la libreria si trova in una cartella diversa da quella dedicata alle librerie (''/user/lib/''), sarà necessario specificare anche il percorso.
  
Possiamo, dunque, dire che è un po' come se ''Extern'' annunciasse: « ''Farò in modo che il programma utilizzi questa funzione "xxxx(yyy)", la quale non appartiene alle risorse di Gambas, ma si trova in questa libreria: zzzz.so (oppure già precedentemente dichiarata).'' ».
+
Possiamo, dunque, dire che è un po' come se ''Extern'' annunciasse: « ''Farò in modo che il programma utilizzi questa funzione "xxxx(yyy)", la quale non appartiene alle risorse di Gambas, ma si trova nella libreria: zzzz.so'' ».
  
La Libreria, contenente la funzione esterna da richiamare, può essere dichiarata separatamente, e prima della dichiarazione ''Extern'':
 
  
  Library "libreria_esterna:num_vers"
+
=Identificazione e dichiarazione della Libreria contenente la Funzione esterna=
 +
La Libreria, contenente la funzione esterna da richiamare, può essere dichiarata separatamente e prima della dichiarazione ''Extern'' mediante la parola-chiave '''LIBRARY''':
 +
 
 +
  '''Library''' "libreria_esterna:num_vers"
 
   
 
   
  Extern......
+
  Extern ......  
 +
oppure può essere dichiarata alla fine della linea dell'istruzione ''[[Extern:_richiamare_funzioni_esterne_a_Gambas#Dichiarazione_della_Funzione_esterna_mediante_Extern|Extern]]'' mediante la parola '''IN''':
 +
Extern ................. '''In''' "libreria_esterna:num_vers"
 +
===Gestione del numero della versione della Libreria===
 +
Se è presente anche il numero della versione della Libreria, esso va scritto così come riportato nel file, e la parte relativa all'estensione <FONT Color=red>''.so.''</font> va sostituita con il carattere dei due punti ( <FONT Color=red>''':'''</font> ).
 +
<BR>Facciamo l'esempio della Libreria ''libsane<FONT Color=red>.so.</font><FONT Color=blue>1.3.1</font>'' .
 +
<BR>Essa sarà scritta così:
 +
Library "libsane<FONT Color=red>''':'''</font><FONT Color=blue>1.3.1</font>"
 +
Se dichiareremo la Libreria alla fine della linea dell'istruzione ''Extern'', si scriverà in modo analogo.
 +
<BR>Così, ad esempio, per dichiarare la funzione "sane_init()" scriveremo:
 +
Private Extern sane_init() In "libsane<FONT Color=red>''':'''</font><FONT Color=blue>1.3.1</font>"
 +
 
 +
Per evitare che la versione della Libreria richiamata non coincida con la versione effettivamente presente in un sistema operativo, si può porre anche solo il primo numero della versione. In tal caso sarà caricata comunque la versione più recente che comincia per il numero indicato.
 +
 
 +
Quindi, invece di scrivere per esempio:
 +
Library "libsane:1.3.1"
 +
si scriverà semplicemente:
 +
Library "libsane:1"
  
La Libreria può anche essere dichiarata all'interno dell'istruzione di ''Extern'':
+
Al fine, poi, di non incorrere in un errore nel richiamare la corretta versione della ''Libreria'', è possibile evitare ogni riferimento al numero di versione, indicando così soltanto il puro nome della ''Libreria'' medesima:
 +
Library "libsane"
  
Extern ................. IN "libreria_esterna:num_vers"
+
Ad ogni modo l'opportunità, di richiamare il nome della libreria comprensivo della sua intera versione in dettaglio, sta anche nella circostanza che in caso vi siano presenti più versioni della medesima libreria, sarà richiamata e dunque utilizzata in Gambas la versione prescelta e specificata.
  
Se il numero della versione della Libreria da dichiarare è complesso, esso andrà scritto così come riportato nel file.
+
====Caso in cui la libreria condivisa non riporti il numero di versione====
Facciamo l'esempio della Libreria ''libsane.so.1.0.23''. Essa sarà scritta così:
+
Qualora  la libreria condivisa, da dichiarare, non riporti il numero di versione, sarà semplicemente dichiarata senza i caratteri finali ".so".
  
  Library "libsane:1.0.23"
+
Così ad esempio la libreria condivisa "libcli.so" sarà dichiarata come segue:
 +
  Library "libcli"
  
Ugualmente, se la dichiareremo all'interno dell'istruzione di ''Extern'', per chiamare ad esempio la funzione ''sane_init()'':
+
==Richiamare una libreria non istallata nel sistema==
 +
Qualora la libreria esterna, che intendiamo utilizzare, non sia presente tra i file di sistema, ma sia stata da noi scaricata in una determinata Cartella (''Directory''), allora con l'istruzione ''Library'' andrà richiamato il nome della libreria esterna, nelle modalità già sopra esposte, comprensivo dell'intero suo percorso.
  
  Private Extern sane_init() In "libsane:1.0.23"
+
Mostriamo un esempio astratto, nel quale verrà richiamata una ipotetica "libreria_esterna.so.1.2.3" , da noi scaricata nella cartella "/tmp":
 +
  Library "/tmp/libreria_esterna:1.2.3"
  
  
La funzione vera e propria, da richiamare per il suo utilizzo, sarà posta all'interno di una routine. Dunque, nel caso di dichiarazione separata della Libreria, la scaletta delle dichiarazioni sarà la seguente:
+
=Dichiarazione della Funzione esterna mediante ''Extern''=
 +
La Funzione esterna, che intendiamo utilizzare, deve essere formalmente dichiarata mediante l'istruzione '''EXTERN'''.
 +
<BR>Questa dichiarazione va effettuata <U>una sola volta</u>, <U>esternamente</u> e <U>prima</u> della routine ove la funzione esterna verrà utilizzata. A tal riguardo, <U>non</u> è necessario che la funzione esterna venga dichiarata proprio ''immediatamente'' prima, a ridosso della routine ove sarà utilizzata. Ciò che importa è che essa sia dichiarata in anticipo rispetto al suo utilizzo in routine.
 +
 
 +
La dichiarazione deve contenere:
 +
<BR>1) il nome della funzione esterna da utilizzare;
 +
<BR>2) la specificazione degli eventuali argomenti della funzione esterna (espressi ovviamente secondo le modalità del linguaggio Gambas);
 +
<BR>3) l'eventuale valore ritornato dalla funzione esterna.
 +
 
 +
La dichiarazione di una Funzione esterna può essere "''Publica''" o "''Privata''".
 +
 
 +
Una Funzione esterna dichiarata in C, ad esempio, in questo modo:
 +
int nome_funzione(int valore1, char valore2)
 +
in Gambas verrà dichiarata con ''Extern'' nella seguente maniera:
 +
Private <Font Color=#B22222>Extern</font> nome_funzione(valore1 As Integer, valore2 As Byte) As Integer
 +
oppure, se si intende dichiararla come ''Pubblica'', si avrà ovviamente:
 +
Public <Font Color=#B22222>Extern</font> ......
 +
 
 +
 
 +
=Ordine delle dichiarazioni nel codice del programma=
 +
La funzione vera e propria, da richiamare per il suo utilizzo, sarà posta ovviamente all'interno di una routine del codice del programma.
 +
 
 +
Dunque, nel caso di dichiarazione separata della Libreria (ossia nel caso di uso dell'istruzione '''Library'''), la scaletta delle dichiarazioni sarà la seguente:
 
<BR>1) dichiarazione della '''Libreria''' contenente la funzione;
 
<BR>1) dichiarazione della '''Libreria''' contenente la funzione;
<BR>2) dichiarazione mediante '''''Extern''''' della funzione esterna che si andrà ad utilizzare (questa dichiarazione avverrà <SPAN style="text-decoration:underline">al di fuori</span> della routine che farà uso di quella funzione);
+
<BR>2) dichiarazione mediante '''''Extern''''' della funzione esterna che si andrà ad utilizzare (questa dichiarazione avverrà <SPAN style="text-decoration:underline">al di fuori</span> e <SPAN style="text-decoration:underline">prima</span> della routine che farà uso di quella funzione);
<BR>3) chiamata ed uso della '''funzione'''.
+
<BR>3) chiamata ed uso della '''funzione''' esterna.
  
 
Esempio astratto:
 
Esempio astratto:
 
+
  <Font Color= #006400>' ''Dichiariamo la Libreria contenente la funzione esterna che ci interessa:''</font>
  ''<Font Color= #006400>' Gambas class file''</font>
 
 
''<Font Color= #006400>' dichiariamo la Libreria contenente la funzione esterna che ci interessa:''</font>
 
 
  <Font Color= #FF0000>Library "libreria_esterna:num_vers"</font>
 
  <Font Color= #FF0000>Library "libreria_esterna:num_vers"</font>
 
   
 
   
 
   
 
   
  ''<Font Color= #006400>' dichiariamo la funzione esterna specifica che ci interessa.
+
  <Font Color= #006400>' ''Ora dichiariamo la funzione esterna specifica che ci interessa.
  '' ' Ipotizziamo che in C sia così scritta: '''int funzione_esterna_da_richiamare(char * valoreStringa, int valoreInteger)'''.
+
  ' ''Ipotizziamo che in C sia così scritta: '''int funzione_esterna(short int valore1, int valore2)'''.
  '' ' Alla funzione esterna vanno passati due valori: uno è una Stringa, l'altro è un Integer. Essa restituirà un valore Integer.
+
  ' ''La funzione esterna, dunque, richiede che le siano passati due valori: uno è di tipo Short, l'altro è un Integer. Essa, poi, restituirà un valore Integer.
  '' ' In Gambas la dichiameremo così:''</font>
+
  ' ''In Gambas la dichiameremo così:''</font>
  Private <Font Color= #FF0000>EXTERN funzione_esterna_da_richiamare(valoreA As String, ValoreB As Integer) As Integer</font>
+
  Private <Font Color= #FF0000>Extern funzione_esterna(valore1 As Short, valore2 As Integer) As Integer</font>
 
   
 
   
'''Public''' Sub routine_esempio(primoValore As String, secondoValore As Integer)  ''<Font Color= #006400>' poniamo il caso che vengano passati i due valori alla routine necessari per la funzione esterna.''</font>
 
 
   
 
   
  Dim vlr1 As String
+
  Public Sub Main()
Dim vlr2 As Integer
 
Dim rit_funz As Integer
 
 
   
 
   
  ''<Font Color= #006400>' chiamiamo la funzione esterna che ci interessa,
+
  Dim primoValore As Short
'' ' e le passiamo i due valori ricevuti dalla routine, perché li elabori.
+
  Dim secondoValore As Integer
  '' ' Coerentemente con la dichiarazione con Extern i due valori (vlr1, vlr2) saranno una Stringa ed un Integer:''</font>
+
  Dim rit_funz As Integer
  <Font Color= #FF0000>rit_funz = funzione_esterna_da_richiamare(vlr1, vlr2)</font>
+
 
 +
  primoValore = 1000
 +
 
 +
  secondoValore = 100000
 +
 
 +
  <Font Color= #006400>' ''Invochiamo la funzione esterna che ci interessa, e le passiamo i due valori, affinché li elabori.''
 +
  ' ''Essa ritornerà per "valore" un dato di tipo Intero.''</font>
 +
  <Font Color= #FF0000>rit_funz = funzione_esterna(primoValore, secondoValore)</font>
 +
 
 +
<Font Color= #006400>' ''Vediamo in console il valore ritornato dalla funzione esterna:''</font>
 +
  Print rit_funz
 +
 
 +
End
 +
 
 +
===Ordine in caso di dichiarazione di più funzioni esterne della medesima Libreria===
 +
Se di una Libreria esterna devono essere utilizzate due o più funzioni, si procederà ovviamente a una dichiarazione per ciascuna funzione esterna da usare.
 +
<BR>Le dichiarazioni formali delle funzioni, appartenenti ad una medesima Libreria esterna, possono essere poste in successione.
 +
 
 +
Esempio astratto:
 +
<Font Color= #006400>' ''Dichiariamo la Libreria contenente le funzioni esterne che intendiamo utilizzare:''</font>
 +
<Font Color= #FF0000>Library "libreria_esterna:num_vers"</font>
 +
 +
 +
<Font Color= #006400>' ''Dichiariamo una funzione esterna che utilizzeremo:''</font>
 +
<Font Color= #FF0000>Private Extern funzione_esterna_1(valore1 As Integer) As Integer</font>
 
   
 
   
  Print rit_funz
+
<Font Color= #006400>' ''Dichiariamo l'altra funzione esterna che utilizzeremo:''</font>
 +
<Font Color= #FF0000>Private Extern funzione_esterna_2(valore1 As Byte) As Integer</font>
 
   
 
   
  '''End'''
+
  ...e così via.
 +
 
 +
 
 +
=Uso del nome di una funzione già utilizzato da Gambas=
 +
Qualora si debba utilizzare una funzione esterna avente il nome identico ad una funzione propria di Gambas, è necessario formalmente usare un nome diverso indicando fra doppi apici, però, nella dichiarazione con ''Extern'' il vero nome della funzione esterna preceduto dal comando ''Exec''.
 +
<BR>Se il prototipo della funzione omonima esterna di C possiede parentesi tonde contenenti uno o più ''parametri formali'', viene riportato con ''Exec'' il solo nome della funzione esterna <SPAN Style="text-decoration:underline">senza</span> le parentesi e i parametri contenuti.
 +
 
 +
Nel seguente esempio pratico dobbiamo dichiarare ed usare la funzione "kill()" presente nella libreria esterna ''libc.so.6'':
 +
int kill(pid_t pid, int sig)
 +
Il nome della funzione esterna "kill()", però, è - come si nota - identico alla funzione "[http://gambaswiki.org/wiki/lang/kill?l=it Kill]" propria di Gambas <SUP>&#091;[[#Note|nota 4]]&#093;</sup>. Pertanto, assegneremo alla funzione esterna un nome qualsiasi, purché diverso da quello di ogni altra funzione di Gambas, ma richiameremo il suo vero nome (senza parentesi tonde e parametri formali contenuti) all'atto della dichiarazione della funzione esterna, facendolo precedere dal comando ''Exec'':
  
 +
Private Extern <FONT Color=Blue>kill_C</font>(pid AS Integer, sig AS Integer) AS Integer In "libc:6" <FONT Color=#B22222><B>Exec "kill"</b></font>
  
====Uso di due o più funzioni esterne contenute ciascuna in una diversa Libreria====
+
Analogamente, se è stata utilizzata l'istruzione ''Library'' per dichiarare la libreria esterna che si intende utilizzare:
 +
Library "libc:6"
 +
 +
Private Extern <FONT Color=Blue>kill_C</font>(pid AS Integer, sig AS Integer) AS Integer <FONT Color=#B22222><B>Exec "kill"</b></font>
  
Può accadere la necessità di utilizzare funzioni che sono contenute in due o più Librerie. In tal caso bisogna ricordare che la dichiarazione di una Libreria influenzerà ogni dichiarazione con ''Extern'' successiva. Cosicché, in questo caso, bisognerà dichiarare la Libreria corrispondente <SPAN style="text-decoration:underline">prima</span> di ''Extern'' e della routine contenente la funzione da utilizzare:
 
  
  <Font Color= #FF0000>Library "1^_libreria_esterna:num_vers"</font>
+
=Uso di funzioni esterne di più Librerie=
 +
Può accadere la necessità di utilizzare le funzioni esterne di due o più Librerie.
 +
===Librerie dichiarate prima delle routine di una Classe o di un Modulo===
 +
Nel caso in cui si intenda dichiarare due o più Librerie esterne prima delle routine di una Classe o di un Modulo, esse potranno essere dichiarate tranquillamente all'<SPAN style="text-decoration:underline">inizio</span> della Classe o del Modulo sia con la parola-chiave "'''Library'''" sia con la parola-chiave "'''In'''".
 +
<BR>Qualora la dichiarazione della libreria esterna venga effettuata con la parola-chiave "''Library''", poiché la dichiarazione di una libreria esterna  influenza ogni dichiarazione con "Extern" del prototipo di una funzione esterna successiva, è necessario dichiarare la Libreria - contenente tale prototipo di funzione - <SPAN style="text-decoration:underline">prima</span> della dichiarazione con ''Extern''.
 +
  <Font Color=Red>Library "libreria_1:num_vers"</font>
 +
 +
Private Extern funzione_esterna_della_libreria_1(......)
 +
 
   
 
   
  Private <Font Color= #FF0000>EXTERN funzione_esterna(valoreA As ..., ValoreB As ...) As ...</font>
+
  <Font Color=Blue>Library "libreria_2:num_vers"</font>
 
   
 
   
  '''Public''' Sub prima_routine_esempio(Aval As ..., Bval As ....)
+
  Private Extern funzione_esterna_della_libreria_2(......)
  ...... ''<Font Color= #006400>' qui l'uso della 1^ funzione esterna''</font>
 
'''End'''
 
 
   
 
   
 
   
 
   
  <Font Color= #FF0000>Library "2^_libreria_esterna:num_vers"</font>
+
  <Font Color= #006400>' ''Quindi di seguito le varie sub-routine della Classe o del Modulo
 +
......
 +
......''</font>
 +
===Librerie dichiarate fra una routine e l'altra di una Classe o di un Modulo===
 +
Qualora si intenda dichiarare le librerie esterne con la parola chiave "''Library''" non all'inizio della Classe, ma all'interno fra una routine e l'altra, poiché - come già detto - la dichiarazione di una Libreria influenza ogni dichiarazione con ''Extern'' successiva, bisogna dichiarare la Libreria corrispondente <SPAN style="text-decoration:underline">prima</span> di ''Extern'' e <SPAN style="text-decoration:underline">prima</span> della routine contenente la funzione da utilizzare.
 +
<Font Color=red>Library "libreria_1:num_vers"</font>
 
   
 
   
  Private <Font Color= #FF0000>EXTERN funzione_esterna(valoreC As ..., ValoreD As ...) As ...</font>
+
  Private Extern funzione_esterna_della_libreria_1(valoreA As ..., ValoreB As ...) As ...
 
   
 
   
  '''Public''' Sub seconda_routine_esempio(Cval As ..., Dval As ...)
+
   
   ...... ''<Font Color= #006400>' qui l'uso della 2^ funzione esterna''</font>
+
Public Sub prima_routine_esempio(Aval As ..., Bval As ....)
  '''End'''
+
  ......<Font Color= #006400>' ''qui l'uso della funzione esterna della libreria_1''</font>
 +
End
 +
 +
 +
<Font Color=Blue>Library "libreria_2:num_vers"</font>
 +
 +
Private Extern funzione_esterna_della_libreria_2(valoreC As ..., ValoreD As ...) As ...
 +
 +
 +
Public Sub seconda_routine_esempio(Cval As ..., Dval As ...)
 +
   ......<Font Color= #006400>' ''qui l'uso della funzione esterna della libreria_2''</font>
 +
  End
  
 
Qualora nell'esempio precedente fosse necessario richiamare, per utilizzare, una funzione esterna presente nella 1^ Libreria, si dovrà dichiarare <SPAN style="text-decoration:underline">nuovamente</span> la 1^ Libreria.
 
Qualora nell'esempio precedente fosse necessario richiamare, per utilizzare, una funzione esterna presente nella 1^ Libreria, si dovrà dichiarare <SPAN style="text-decoration:underline">nuovamente</span> la 1^ Libreria.
  
  
===Esempi pratici===
+
=Esempi pratici=
 +
Mostriamo appresso un semplice esempio pratico utilizzando la funzione esterna ''usleep( )'' dichiarata nel file header di sistema "''/usr/include/unistd.h''", la quale provoca una sospensione dell'esecuzione del programma per un intervallo di microsecondi (µs) indicati nel primo argomento della funzione esterna medesima.
  
Mostriamo appresso un esempio pratico utilizzando una funzione ''esterna'' di ALSA{[[#Note|2]]}.
+
Facendo ancora riferimento ai tre punti esposti all'inizio, avremo:
  
1) Il ''quid'':
+
'''1''') Il ''quid'':
vogliamo far sì che il nostro applicativo si connetta con ALSA o con un client;
+
vogliamo far sì che il nostro applicativo resti in attesa per 3500000 microsecondi;
  
2) per ottenere questo risultato sappiamo che è necessario richiamare una <SPAN style="text-decoration:underline">specifica, particolare</span> funzione ''esterna'' di ALSA:
+
'''2''') per ottenere questo risultato sappiamo che è necessario richiamare una <SPAN style="text-decoration:underline">specifica, particolare</span> funzione ''esterna'', che sarebbe ''usleep()'', e che è dichiarata nel file header di sistema "''/usr/include/unistd.h''" come segue:  
''<Font Color= #B22222>int snd_seq_connect_to(snd_seq_t *seq, int my_port, int dest_client, int dest_port)''</font>
+
''int usleep (__useconds_t __useconds)''
<BR>Questa funzione va così interpretata:
+
Questa funzione va così interpretata:
 
<BR>- ''<Font Color= #B22222>int''</font> : vuol dire che ritorna un valore integer;
 
<BR>- ''<Font Color= #B22222>int''</font> : vuol dire che ritorna un valore integer;
<BR>- ''<Font Color= #B22222>snd_seq_connect_to''</font> : è la funzione in sé;
+
<BR>- ''<Font Color= #B22222>usleep''</font> : è il nome identificatore della funzione;
<BR>- ''<Font Color= #B22222>(snd_seq_t *seq, int my_port, int dest_client, int dest_port)''</font> : sono i parametri della funzione. In questo caso: un Pointer (definito dal simbolo '''*''') e tre valori Integer (definiti da ciascun ''int'');
+
<BR>- ''<Font Color= #B22222>(__useconds_t __useconds)''</font> : è il parametro della funzione esterna, in questo caso occupa 4 byte e, dunque, in Gambas equivale a un ''Integer''.
  
In Gambas sarà così tradotta:
+
In Gambas questa funzione esterna sarà, dunque, così tradotta:
<BR>''snd_seq_connect_to(1°valore As Pointer, 2°valore As Integer, 3°valore As Integer, 4°valore As Integer) As Integer'' (quest'ultimo "''As Integer''" è ovviamente giustificato dal fatto che la funzione, come sappiamo, restituisce un valore ''integer'');
+
Extern usleep(__useconds As Integer) As Integer
 
+
quest'ultimo "''As Integer''" (esterno ai parametri specifici della funzione esterna) è ovviamente giustificato dal fatto che detta funzione esterna restituisce un "int", ossia un valore ''intero'' che occupa 4 byte di memoria;
3) il ''luogo'' ove questa funzione è contenuta: questa funzione è presente nella Libreria contenente le funzioni di ALSA: Libasound.'''so'''.2 .
 
  
 +
'''3''') il ''luogo'' ove questa funzione è contenuta: questa funzione è presente nella Libreria dinamica condivisa "''libc.so.6''".
  
 
Il tutto, allora, sarebbe così da impostarsi:
 
Il tutto, allora, sarebbe così da impostarsi:
 +
<Font Color= #006400>' ''Dichiarazione della Libreria contenente la funzione esterna che si intende utilizzare:''</font>
 +
Library "libc:6"
 +
 
 +
<Font Color= #006400>' ''Dichiarazione mediante "Extern" della funzione esterna da utilizzare:''</font>
 +
<Font Color=gray>' ''int usleep (__useconds_t __useconds)''
 +
' ''Sleep USECONDS microseconds.''</font>
 +
Private Extern usleep(__useconds As Integer) As Integer
 +
 +
 +
Public Sub Main()
 +
 
 +
  Dim i As Integer
 +
 
 +
  Print "Attesa..."
 +
   
 +
<Font Color= #006400>' ''Viene praticamente richiamata ed utilizzata la funzione esterna, e le si passa il valore (µs 3500000) come suo argomento:''</font>
 +
  i = usleep(3500000)
 +
  If i < 0 Then Error.Raise("Errore alla funzione 'usleep()' !")
 +
 
 +
  Print "Fine programma"
 +
 
 +
End
  
''<Font Color= #006400>' Dichiarazione della Libreria contenente la funzione esterna che si intende utilizzare:''</font>
 
<BR>Library "libasound:2"
 
  
....
+
Altro esempio pratico, ma ora utilizzando la funzione esterna ''modf( )'' della libreria delle funzioni matematiche ''libm.so.6'' :
 +
<Font Color= #006400>' ''Dichiarazione della Libreria contenente la funzione esterna da utilizzare:''</font>
 +
Library "libm:6"
 +
 +
<Font Color= #006400>' ''Dichiarazione mediante Extern della funzione esterna da utilizzare:''</font>
 +
<Font Color=gray>' ''modf (_Mdouble_ __x, _Mdouble_ *__iptr)''
 +
' ''Break VALUE into integral and fractional parts.''</font>
 +
Private Extern modf(__x As Float, __iptr As Pointer) As Float
 +
 
 +
 
 +
Public Sub Main()
 +
 
 +
  Dim f, intero, frazione As Float
 +
 
 +
  f = 5.123456
 +
 
 +
<Font Color= #006400>' ''Uso della funzione esterna:''</font>
 +
  frazione = modf(f, VarPtr(intero))
 +
 
 +
<Font Color= #006400>' ''Mostra in console il risultato:''</font>
 +
  Print "Parte intera: "; intero
 +
  Print "Parte decimale: "; frazione
 +
 
 +
End
  
''<Font Color= #006400>' Extern dichiara la funzione esterna che si intende richiamare ed utilizzare (lasciamo per comodità qui i nomi: 1°valore, etc, precedentemente usati):''</font>
 
<BR>Private Extern snd_seq_connect_to(1°valore As Pointer, 2°valore As Integer, 3°valore As Integer, 4°valore As Integer) As Integer
 
  
Public Sub .....()
+
=Funzione esterna che fa riferimento ad una funzione interna ''Callback''=
 +
Alcune funzioni esterne possono avere nei propri parametri riferimenti ad altre funzioni interne al codice dell'applicativo usate come ''callback'' (o ''gestore dell'evento'') per gestire eventi asincroni. Sostanzialmente viene detto alla libreria quando far accedere un evento, e soprattutto ''come'', che nella funzione esterna viene espresso appunto dalla funzione ''callback''. Dunque viene detto alla libreria, una volta sola e prima di tutto, come fare a raggiungere il gestore dell'evento. Quando è il momento, la libreria invoca la funzione interna ''callback'', passandogli eventualmente dei valori come argomenti. Tali argomenti, dunque, sono valori che vengono semplicemente passati alla funzione interna ''callback''.
 +
<BR>Le funzioni di ''callback'', definite così perché vengono ''attivate'' non dal programmatore ma dal codice interno, sono ideali per i casi in cui un'attività viene eseguita ripetutamente.  
  
Dim 1val As Pointer
+
<BR>Nella funzione esterna la funzione ''callback'' viene espressa semplicemente indicando il suo nome.
<BR> Dim err As Integer
+
Ad esempio potremmo avere un funzione esterna scritta in C:
<BR>Dim 2val, 3val, 4val As Integer
+
''int <FONT color=#6495ed>'''funzione_esterna_callback'''</font>(...... *param1, <FONT color=#B22222>funzione_callback</font>, void *param3)''
  
''<Font Color= #006400>' viene praticamente richiamata ed utilizzata la funzione esterna, e le si passano i quattro valori da essa richiesti:''</font>
 
<BR>err = snd_seq_connect_to(1val, 2val, 3val, 4val)
 
  
......
+
In Gambas all'atto della dichiarazione della funzione esterna con ''Extern'' la funzione ''callback'' viene dichiarata, quale argomento della predetta funzione esterna, come variabile di tipo <SPAN style="text-decoration:underline">''Puntatore''</span>. Essa potrà assumere un nome qualsiasi, dato che in questa fase esso non è fondamentale.
 +
<BR>Pertanto, la funzione esterna dell'esempio precedente in Gambas sarà così espressa:
 +
Private Extern <FONT color=#6495ed>'''funzione_esterna_callback'''</font>(param1 As Pointer, <FONT color=#B22222><B>funzione_callback</b></font> <FONT color=#0000FF>'''As Pointer'''</font>, param3 As Pointer) As Integer
  
End
 
  
 
+
====Esempio astratto====
----
+
Poniamo che la funzione espressa in C sia quella indicata appena sopra. In Gambas avremo:
 
+
Private Extern <FONT color=#6495ed>'''funzione_esterna_callback'''</font>(param1 As Pointer, <FONT color=#B22222><B>funzione_callback</b></font> <FONT color=#0000FF>'''''As Pointer'''''</font>, param3 As Pointer) As Integer
 
+
Altro esempio:
+
 
+
Public Sub esempio()
  ''<Font Color= #006400>' Dichiarazione della Libreria contenente le funzioni esterne da utilizzare''
+
''(in questo esempio la libreria delle funzioni matematiche):''</font>
+
  Dim rit As Integer
Library "libm:6"
+
  Dim val1, val2 As Pointer
 +
 +
  val1 = una_qualsiasi_funzione_esterna(.........)
 +
 
 +
  <Font Color= #006400>' ''Viene invocata la funzione esterna, la quale a sua volta richiama la funzione interna "callback"'':</font>
 +
  rit = <FONT color=#6495ed>'''funzione_esterna_callback'''</font>(val1, <FONT color=#B22222>'''funzione_interna_callback'''</font>, val2)
 
   
 
   
  ''<Font Color= #006400>' Dichiarazione mediante Extern delle funzioni esterne da utilizzare:''</font>
+
  End
Private Extern modf(param As Float, pp As Pointer) As Float
 
Private Extern fmod(param1 As Float, param2 As Float) As Float
 
 
   
 
   
'''Public''' Sub Button1_Click()
 
 
   
 
   
  Dim pp As Pointer = Alloc(SizeOf(gb.Float))
+
  Private Function <FONT color=#B22222><B>funzione_interna_callback</b></font>(vlr As Pointer, data As Pointer)
 
   
 
   
  ''<Font Color= #006400>' Uso delle funzioni esterne:''</font>
+
<Font Color= #006400>' ''Qui il codice specifico della funzione interna "callback"''</font>
    Print modf(5.123456, pp)
+
  ......
    Print fmod(5.654321, 2)
 
 
   
 
   
  '''End'''
+
  End
 +
 
 +
 
 +
 
 +
=Note=
 +
['''1'''] Prendiamo come esempio il possibile diretto rapporto fra Gambas ed il sistema sonoro ALSA: attualmente non esiste uno specifico Componente di Gambas per richiamare e gestire direttamente le risorse di ALSA.
 +
<BR>Così, se non si avesse in alcun modo la possibilità di richiamare e quindi di utilizzare le specifiche funzioni di ALSA, non sarebbe possibile ''interloquire'' in modo diretto con questo sistema esterno mediante il linguaggio Gambas. Non sarebbe insomma possibile con il codice Gambas utilizzare le funzioni di ALSA e quindi le sue potenzialità.
 +
<BR>L'istruzione ''Extern'' ci consente di superare questo muro, questo limite.
 +
 
 +
['''2'''] La "Dichiarazione" di una Funzione introduce e specifica la Funzione medesima.
 +
 
 +
['''3'''] Una libreria condivisa (''Shared Library'') è un file binario contenente un insieme di funzioni richiamabili o classi. Esse hanno un nome particolare, detto ''soname'', composto dalle lettere iniziali "''lib''", dal nome specifico della libreria, dall'estensione "''.so''", nonché solitamente da un punto e da uno o più numeri, separati da un punto, che rappresentano il ''numero di versione'' della libreria.
 +
<BR>Esempio:
 +
<FONT Color=brown>lib</font><FONT Color=green>sane</font><FONT Color=red>'''.so'''</font><FONT Color=blue>.1.3.1</font>
 +
 
 +
['''4'''] E' identico, eccezione fatta per la prima lettera del nome della funzione che in Gambas è comunque sempre maiuscola.
  
==Note==
 
  
[1] Prendiamo come esempio il rapporto fra Gambas ed il sistema sonoro ALSA. Se non si avesse la possibilità di richiamare, e quindi di utilizzare le funzioni proprie di ALSA, non sarebbe possibile ''interloquire'' con questo sistema esterno. Non sarebbe possibile gestirne le capacità, e dunque utilizzare le sue funzioni e potenzialità. L'istruzione ''Extern'' ci consente di superare questo muro, questo limite.
 
  
[2] Gli applicativi per la gestione del Midi, presenti nella pagina "''Progetti degli utenti''" del Forum e nell'area "''Download''" di questo portale ''Gambas-it.org'', abbondano di richiami alle funzioni esterne delle API di ALSA.
+
=Riferimenti=
 +
Sono <FONT Color=red>assolutamente da leggere</font> i seguenti riferimenti:
 +
* http://gambaswiki.org/wiki/lang/extdecl
 +
* http://gambaswiki.org/wiki/doc/extern
 +
* http://gambaswiki.org/wiki/lang/externfunc

Versione attuale delle 15:11, 3 set 2024

Introduzione

Gambas consente di utilizzare potenzialità e capacità di sistemi (risorse) esterni implementandoli nel linguaggio attraverso i suoi Componenti.
Gambas, però, non implementa tutte le migliaia di risorse informatiche disponibili, e talvolta può capitare nella programmazione la necessità di utilizzare funzionalità che la corrente versione di Gambas, essendone priva, non può direttamente offrire [nota 1]; funzionalità che sono comunque espresse - come già detto - da sistemi esterni.
Gambas consente di fruire di tali potenzialità esterne, ponendo disposizione del programmatore, per richiamare tali funzioni esterne, l'istruzione è: EXTERN.

Per il richiamo di funzioni esterne è necessario conoscere in particolare tre elementi:

  • il quid, ossia il cosa fare, cosa ottenere;
  • la funzione esterna che ci consente di realizzare quel quid;
  • la libreria nella quale è contenuta la funzione da richiamare.

Se quel che si vuole ottenere è possibile solamente attraverso l'uso di una funzione esterna a Gambas, bisognerà individuare tale specifica funzione esterna che consente di realizzare il nostro obiettivo, e dichiararla nel nostro programma Gambas e esso richiamarla. Poiché tale funzione esterna è scritta in C, bisognerà interpretare il significato della sua dichiarazione originaria [nota 2], espressa in C, e tradurla in forma comprensibile a Gambas.
Inoltre, poiché essa è appunto esterna a Gambas, bisognerà conoscere il luogo ove essa si trova. Il luogo che contiene la funzione esterna è la "Libreria"; ed anzi una specifica libreria, la quale, pertanto, andrà dichiarata in anticipo rispetto alla funzione. Le librerie, contenenti funzioni esterne a Gambas, richiamabili da Gambas, sono quelle con estensione .so, ossia le "Librerie condivise " [nota 3]. E' opportuno, quando possibile, indicare anche il numero della versione della Libreria.
Se la libreria si trova in una cartella diversa da quella dedicata alle librerie (/user/lib/), sarà necessario specificare anche il percorso.

Possiamo, dunque, dire che è un po' come se Extern annunciasse: « Farò in modo che il programma utilizzi questa funzione "xxxx(yyy)", la quale non appartiene alle risorse di Gambas, ma si trova nella libreria: zzzz.so ».


Identificazione e dichiarazione della Libreria contenente la Funzione esterna

La Libreria, contenente la funzione esterna da richiamare, può essere dichiarata separatamente e prima della dichiarazione Extern mediante la parola-chiave LIBRARY:

Library "libreria_esterna:num_vers"

Extern ...... 

oppure può essere dichiarata alla fine della linea dell'istruzione Extern mediante la parola IN:

Extern ................. In "libreria_esterna:num_vers"

Gestione del numero della versione della Libreria

Se è presente anche il numero della versione della Libreria, esso va scritto così come riportato nel file, e la parte relativa all'estensione .so. va sostituita con il carattere dei due punti ( : ).
Facciamo l'esempio della Libreria libsane.so.1.3.1 .
Essa sarà scritta così:

Library "libsane:1.3.1"

Se dichiareremo la Libreria alla fine della linea dell'istruzione Extern, si scriverà in modo analogo.
Così, ad esempio, per dichiarare la funzione "sane_init()" scriveremo:

Private Extern sane_init() In "libsane:1.3.1"

Per evitare che la versione della Libreria richiamata non coincida con la versione effettivamente presente in un sistema operativo, si può porre anche solo il primo numero della versione. In tal caso sarà caricata comunque la versione più recente che comincia per il numero indicato.

Quindi, invece di scrivere per esempio:

Library "libsane:1.3.1"

si scriverà semplicemente:

Library "libsane:1"

Al fine, poi, di non incorrere in un errore nel richiamare la corretta versione della Libreria, è possibile evitare ogni riferimento al numero di versione, indicando così soltanto il puro nome della Libreria medesima:

Library "libsane"

Ad ogni modo l'opportunità, di richiamare il nome della libreria comprensivo della sua intera versione in dettaglio, sta anche nella circostanza che in caso vi siano presenti più versioni della medesima libreria, sarà richiamata e dunque utilizzata in Gambas la versione prescelta e specificata.

Caso in cui la libreria condivisa non riporti il numero di versione

Qualora la libreria condivisa, da dichiarare, non riporti il numero di versione, sarà semplicemente dichiarata senza i caratteri finali ".so".

Così ad esempio la libreria condivisa "libcli.so" sarà dichiarata come segue:

Library "libcli"

Richiamare una libreria non istallata nel sistema

Qualora la libreria esterna, che intendiamo utilizzare, non sia presente tra i file di sistema, ma sia stata da noi scaricata in una determinata Cartella (Directory), allora con l'istruzione Library andrà richiamato il nome della libreria esterna, nelle modalità già sopra esposte, comprensivo dell'intero suo percorso.

Mostriamo un esempio astratto, nel quale verrà richiamata una ipotetica "libreria_esterna.so.1.2.3" , da noi scaricata nella cartella "/tmp":

Library "/tmp/libreria_esterna:1.2.3"


Dichiarazione della Funzione esterna mediante Extern

La Funzione esterna, che intendiamo utilizzare, deve essere formalmente dichiarata mediante l'istruzione EXTERN.
Questa dichiarazione va effettuata una sola volta, esternamente e prima della routine ove la funzione esterna verrà utilizzata. A tal riguardo, non è necessario che la funzione esterna venga dichiarata proprio immediatamente prima, a ridosso della routine ove sarà utilizzata. Ciò che importa è che essa sia dichiarata in anticipo rispetto al suo utilizzo in routine.

La dichiarazione deve contenere:
1) il nome della funzione esterna da utilizzare;
2) la specificazione degli eventuali argomenti della funzione esterna (espressi ovviamente secondo le modalità del linguaggio Gambas);
3) l'eventuale valore ritornato dalla funzione esterna.

La dichiarazione di una Funzione esterna può essere "Publica" o "Privata".

Una Funzione esterna dichiarata in C, ad esempio, in questo modo:

int nome_funzione(int valore1, char valore2)

in Gambas verrà dichiarata con Extern nella seguente maniera:

Private Extern nome_funzione(valore1 As Integer, valore2 As Byte) As Integer

oppure, se si intende dichiararla come Pubblica, si avrà ovviamente:

Public Extern ......


Ordine delle dichiarazioni nel codice del programma

La funzione vera e propria, da richiamare per il suo utilizzo, sarà posta ovviamente all'interno di una routine del codice del programma.

Dunque, nel caso di dichiarazione separata della Libreria (ossia nel caso di uso dell'istruzione Library), la scaletta delle dichiarazioni sarà la seguente:
1) dichiarazione della Libreria contenente la funzione;
2) dichiarazione mediante Extern della funzione esterna che si andrà ad utilizzare (questa dichiarazione avverrà al di fuori e prima della routine che farà uso di quella funzione);
3) chiamata ed uso della funzione esterna.

Esempio astratto:

' Dichiariamo la Libreria contenente la funzione esterna che ci interessa:
Library "libreria_esterna:num_vers"


' Ora dichiariamo la funzione esterna specifica che ci interessa.
' Ipotizziamo che in C sia così scritta: int funzione_esterna(short int valore1, int valore2).
' La funzione esterna, dunque, richiede che le siano passati due valori: uno è di tipo Short, l'altro è un Integer. Essa, poi, restituirà un valore Integer.
' In Gambas la dichiameremo così:
Private Extern funzione_esterna(valore1 As Short, valore2 As Integer) As Integer


Public Sub Main()

 Dim primoValore As Short
 Dim secondoValore As Integer
 Dim rit_funz As Integer
 
 primoValore = 1000
  
 secondoValore = 100000
  
' Invochiamo la funzione esterna che ci interessa, e le passiamo i due valori, affinché li elabori.
' Essa ritornerà per "valore" un dato di tipo Intero.
 rit_funz = funzione_esterna(primoValore, secondoValore)
  
' Vediamo in console il valore ritornato dalla funzione esterna:
 Print rit_funz
  
End

Ordine in caso di dichiarazione di più funzioni esterne della medesima Libreria

Se di una Libreria esterna devono essere utilizzate due o più funzioni, si procederà ovviamente a una dichiarazione per ciascuna funzione esterna da usare.
Le dichiarazioni formali delle funzioni, appartenenti ad una medesima Libreria esterna, possono essere poste in successione.

Esempio astratto:

' Dichiariamo la Libreria contenente le funzioni esterne che intendiamo utilizzare:
Library "libreria_esterna:num_vers"


' Dichiariamo una funzione esterna che utilizzeremo:
Private Extern funzione_esterna_1(valore1 As Integer) As Integer

' Dichiariamo l'altra funzione esterna che utilizzeremo:
Private Extern funzione_esterna_2(valore1 As Byte) As Integer

...e così via.


Uso del nome di una funzione già utilizzato da Gambas

Qualora si debba utilizzare una funzione esterna avente il nome identico ad una funzione propria di Gambas, è necessario formalmente usare un nome diverso indicando fra doppi apici, però, nella dichiarazione con Extern il vero nome della funzione esterna preceduto dal comando Exec.
Se il prototipo della funzione omonima esterna di C possiede parentesi tonde contenenti uno o più parametri formali, viene riportato con Exec il solo nome della funzione esterna senza le parentesi e i parametri contenuti.

Nel seguente esempio pratico dobbiamo dichiarare ed usare la funzione "kill()" presente nella libreria esterna libc.so.6:

int kill(pid_t pid, int sig)

Il nome della funzione esterna "kill()", però, è - come si nota - identico alla funzione "Kill" propria di Gambas [nota 4]. Pertanto, assegneremo alla funzione esterna un nome qualsiasi, purché diverso da quello di ogni altra funzione di Gambas, ma richiameremo il suo vero nome (senza parentesi tonde e parametri formali contenuti) all'atto della dichiarazione della funzione esterna, facendolo precedere dal comando Exec:

Private Extern kill_C(pid AS Integer, sig AS Integer) AS Integer In "libc:6" Exec "kill"

Analogamente, se è stata utilizzata l'istruzione Library per dichiarare la libreria esterna che si intende utilizzare:

Library "libc:6"

Private Extern kill_C(pid AS Integer, sig AS Integer) AS Integer Exec "kill"


Uso di funzioni esterne di più Librerie

Può accadere la necessità di utilizzare le funzioni esterne di due o più Librerie.

Librerie dichiarate prima delle routine di una Classe o di un Modulo

Nel caso in cui si intenda dichiarare due o più Librerie esterne prima delle routine di una Classe o di un Modulo, esse potranno essere dichiarate tranquillamente all'inizio della Classe o del Modulo sia con la parola-chiave "Library" sia con la parola-chiave "In".
Qualora la dichiarazione della libreria esterna venga effettuata con la parola-chiave "Library", poiché la dichiarazione di una libreria esterna influenza ogni dichiarazione con "Extern" del prototipo di una funzione esterna successiva, è necessario dichiarare la Libreria - contenente tale prototipo di funzione - prima della dichiarazione con Extern.

Library "libreria_1:num_vers"

Private Extern funzione_esterna_della_libreria_1(......)


Library "libreria_2:num_vers"

Private Extern funzione_esterna_della_libreria_2(......)


' Quindi di seguito le varie sub-routine della Classe o del Modulo
......
......

Librerie dichiarate fra una routine e l'altra di una Classe o di un Modulo

Qualora si intenda dichiarare le librerie esterne con la parola chiave "Library" non all'inizio della Classe, ma all'interno fra una routine e l'altra, poiché - come già detto - la dichiarazione di una Libreria influenza ogni dichiarazione con Extern successiva, bisogna dichiarare la Libreria corrispondente prima di Extern e prima della routine contenente la funzione da utilizzare.

Library "libreria_1:num_vers"

Private Extern funzione_esterna_della_libreria_1(valoreA As ..., ValoreB As ...) As ...


Public Sub prima_routine_esempio(Aval As ..., Bval As ....)
  ......' qui l'uso della funzione esterna della libreria_1
End


Library "libreria_2:num_vers"

Private Extern funzione_esterna_della_libreria_2(valoreC As ..., ValoreD As ...) As ...


Public Sub seconda_routine_esempio(Cval As ..., Dval As ...)
  ......' qui l'uso della funzione esterna della libreria_2
End

Qualora nell'esempio precedente fosse necessario richiamare, per utilizzare, una funzione esterna presente nella 1^ Libreria, si dovrà dichiarare nuovamente la 1^ Libreria.


Esempi pratici

Mostriamo appresso un semplice esempio pratico utilizzando la funzione esterna usleep( ) dichiarata nel file header di sistema "/usr/include/unistd.h", la quale provoca una sospensione dell'esecuzione del programma per un intervallo di microsecondi (µs) indicati nel primo argomento della funzione esterna medesima.

Facendo ancora riferimento ai tre punti esposti all'inizio, avremo:

1) Il quid: vogliamo far sì che il nostro applicativo resti in attesa per 3500000 microsecondi;

2) per ottenere questo risultato sappiamo che è necessario richiamare una specifica, particolare funzione esterna, che sarebbe usleep(), e che è dichiarata nel file header di sistema "/usr/include/unistd.h" come segue:

int usleep (__useconds_t __useconds)

Questa funzione va così interpretata:
- int : vuol dire che ritorna un valore integer;
- usleep : è il nome identificatore della funzione;
- (__useconds_t __useconds) : è il parametro della funzione esterna, in questo caso occupa 4 byte e, dunque, in Gambas equivale a un Integer.

In Gambas questa funzione esterna sarà, dunque, così tradotta:

Extern usleep(__useconds As Integer) As Integer

quest'ultimo "As Integer" (esterno ai parametri specifici della funzione esterna) è ovviamente giustificato dal fatto che detta funzione esterna restituisce un "int", ossia un valore intero che occupa 4 byte di memoria;

3) il luogo ove questa funzione è contenuta: questa funzione è presente nella Libreria dinamica condivisa "libc.so.6".

Il tutto, allora, sarebbe così da impostarsi:

' Dichiarazione della Libreria contenente la funzione esterna che si intende utilizzare:
Library "libc:6"
 
' Dichiarazione mediante "Extern" della funzione esterna da utilizzare:
' int usleep (__useconds_t __useconds)
' Sleep USECONDS microseconds.
Private Extern usleep(__useconds As Integer) As Integer


Public Sub Main()
 
 Dim i As Integer
  
 Print "Attesa..."
   
' Viene praticamente richiamata ed utilizzata la funzione esterna, e le si passa il valore (µs 3500000) come suo argomento:
 i = usleep(3500000)
 If i < 0 Then Error.Raise("Errore alla funzione 'usleep()' !")
 
 Print "Fine programma"
  
End


Altro esempio pratico, ma ora utilizzando la funzione esterna modf( ) della libreria delle funzioni matematiche libm.so.6 :

' Dichiarazione della Libreria contenente la funzione esterna da utilizzare:
Library "libm:6"

' Dichiarazione mediante Extern della funzione esterna da utilizzare:
' modf (_Mdouble_ __x, _Mdouble_ *__iptr)
' Break VALUE into integral and fractional parts.
Private Extern modf(__x As Float, __iptr As Pointer) As Float
 
  
Public Sub Main()
 
 Dim f, intero, frazione As Float
  
 f = 5.123456
  
' Uso della funzione esterna:
 frazione = modf(f, VarPtr(intero))
  
' Mostra in console il risultato:
 Print "Parte intera: "; intero
 Print "Parte decimale: "; frazione
  
End


Funzione esterna che fa riferimento ad una funzione interna Callback

Alcune funzioni esterne possono avere nei propri parametri riferimenti ad altre funzioni interne al codice dell'applicativo usate come callback (o gestore dell'evento) per gestire eventi asincroni. Sostanzialmente viene detto alla libreria quando far accedere un evento, e soprattutto come, che nella funzione esterna viene espresso appunto dalla funzione callback. Dunque viene detto alla libreria, una volta sola e prima di tutto, come fare a raggiungere il gestore dell'evento. Quando è il momento, la libreria invoca la funzione interna callback, passandogli eventualmente dei valori come argomenti. Tali argomenti, dunque, sono valori che vengono semplicemente passati alla funzione interna callback.
Le funzioni di callback, definite così perché vengono attivate non dal programmatore ma dal codice interno, sono ideali per i casi in cui un'attività viene eseguita ripetutamente.


Nella funzione esterna la funzione callback viene espressa semplicemente indicando il suo nome. Ad esempio potremmo avere un funzione esterna scritta in C:

int funzione_esterna_callback(...... *param1, funzione_callback, void *param3)


In Gambas all'atto della dichiarazione della funzione esterna con Extern la funzione callback viene dichiarata, quale argomento della predetta funzione esterna, come variabile di tipo Puntatore. Essa potrà assumere un nome qualsiasi, dato che in questa fase esso non è fondamentale.
Pertanto, la funzione esterna dell'esempio precedente in Gambas sarà così espressa:

Private Extern funzione_esterna_callback(param1 As Pointer, funzione_callback As Pointer, param3 As Pointer) As Integer


Esempio astratto

Poniamo che la funzione espressa in C sia quella indicata appena sopra. In Gambas avremo:

Private Extern funzione_esterna_callback(param1 As Pointer, funzione_callback As Pointer, param3 As Pointer) As Integer


Public Sub esempio()

 Dim rit As Integer
 Dim val1, val2 As Pointer

 val1 = una_qualsiasi_funzione_esterna(.........)
 
' Viene invocata la funzione esterna, la quale a sua volta richiama la funzione interna "callback":
  rit = funzione_esterna_callback(val1, funzione_interna_callback, val2)

End


Private Function funzione_interna_callback(vlr As Pointer, data As Pointer)

' Qui il codice specifico della funzione interna "callback"
  ......

End


Note

[1] Prendiamo come esempio il possibile diretto rapporto fra Gambas ed il sistema sonoro ALSA: attualmente non esiste uno specifico Componente di Gambas per richiamare e gestire direttamente le risorse di ALSA.
Così, se non si avesse in alcun modo la possibilità di richiamare e quindi di utilizzare le specifiche funzioni di ALSA, non sarebbe possibile interloquire in modo diretto con questo sistema esterno mediante il linguaggio Gambas. Non sarebbe insomma possibile con il codice Gambas utilizzare le funzioni di ALSA e quindi le sue potenzialità.
L'istruzione Extern ci consente di superare questo muro, questo limite.

[2] La "Dichiarazione" di una Funzione introduce e specifica la Funzione medesima.

[3] Una libreria condivisa (Shared Library) è un file binario contenente un insieme di funzioni richiamabili o classi. Esse hanno un nome particolare, detto soname, composto dalle lettere iniziali "lib", dal nome specifico della libreria, dall'estensione ".so", nonché solitamente da un punto e da uno o più numeri, separati da un punto, che rappresentano il numero di versione della libreria.
Esempio:

libsane.so.1.3.1

[4] E' identico, eccezione fatta per la prima lettera del nome della funzione che in Gambas è comunque sempre maiuscola.


Riferimenti

Sono assolutamente da leggere i seguenti riferimenti: