In CS StackExchange, ho discusso di come è possibile codificare le funzioni di ordine superiore in termini di puntatori di funzione . Fondamentalmente, una chiusura è solo una coppia di void *
per un ambiente e un puntatore di funzione. Qualcosa come:
struct IntToIntClosure {
void *environment;
int (*func)(void *, int);
}
Ad esempio, nell'API Asynchronous I / O di Linux sigevent
la struttura fa unire queste cose insieme ("l'ambiente" è il campo sigev_value
).
Tuttavia, è molto comune passare un foo *
e una lunghezza separatamente quando foo *
è visto come una matrice, è normale non comprimerli in una struttura dati, ma per passarli come separati parametri. Molte API C che accettano i callback accettano un ulteriore parametro "context" che di solito è un void *
che verrà passato al puntatore della funzione ogni volta che viene chiamato. Ad esempio, on_exit
di glibc (in contrasto con atexit
).
Puoi facilmente codificare le funzioni e gli oggetti di ordine superiore con la spedizione dinamica usando queste tecniche. Tuttavia, se si dispone di un'API che accetta solo i puntatori di funzioni per la registrazione, non è possibile eseguire questo * . Non c'è modo di sapere quale ambiente deve essere associato a quale invocazione di un puntatore di funzione dopo il fatto. In questo caso, sarai costretto a utilizzare variabili globali o statiche per trasferire qualsiasi informazione sull'ambiente con le limitazioni relative a essenzialmente un solo ambiente consentito. Se hai il controllo di questa API, I consiglia strongmente di prendere e memorizzare un parametro aggiuntivo per questo ambiente (esplicitamente o tramite struct
).
* Ci sono trucchi per aggirare questo problema se non ti interessa la portabilità. Se è possibile generare dinamicamente i puntatori di funzione (ad esempio scrivendo il codice macchina in fase di esecuzione) è possibile creare un puntatore a funzione su uno stub che passerà il parametro aggiuntivo alla funzione desiderata. Ecco come GHC Haskell gestisce il passaggio delle funzioni Haskell come callback C.