Domanda

Ho questo programma che voglio altri processi per essere in grado di chiamare funzioni (attraverso prese di Unix). Il protocollo di messaggio è molto semplice, il nome della funzione, una firma di funzione, e un buffer (char *) che contiene i parametri.

Quando un modulo nel mio programma vuole permettere una funzione sia accessibile, si registra il nome e la firma con la libreria. Il problema che sto affrontando è con chiamando fisicamente la funzione una volta che la richiesta arriva. Ho guardato le librerie RPC e Java RMI-like, ma quelli che richiedono genero stub per avvolgere le chiamate. Il sistema di cui sto lavorando è molto dinamico e ho anche di interfacciarsi con il codice di altri popoli che non posso modificare.

Quindi, fondamentalmente, una funzione potrebbe essere simile:

int somefunc(int someparam, double another)
{
    return 1234;
}

ora mi registro con la libreria:

//           func ptr   name       signature
REG_FUNCTION(somefunc, "somefunc", "i:id");

Quando la richiesta arriva, faccio un po 'il controllo degli errori, una volta valido voglio chiamare la funzione. Così ho le variabili:

void * funcptr = (the requested function);
char * sig = (the function signature);
char * params = (a buffer of function parameters);
//note that the params buffer can hold data types of arbitrary lengths

Come posso chiamare la funzione con i parametri in C?

Grazie!

È stato utile?

Soluzione

Non credo che questo è completamente risolvibile in generale, utilizzando solo C. Tu non sai la convenzione di chiamata utilizzata dalla funzione di destinazione, per esempio. V'è il rischio che si finisce per "barare" il compilatore, o almeno di dover indovinare esso. Che cosa succede se il compilatore ha deciso di costruire la funzione registrata utilizzando argomenti passati nei registri, forse a causa di una certa impostazione di ottimizzazione (o quello che se fosse stato costruito con un compilatore diverso?).

C'è anche un modo, in generale, per esprimere in C che si desidera chiamare una funzione con un dato insieme di argomenti, e che i valori per gli argomenti devono essere spacchettato da un buffer di byte casuali.

Si potrebbe fare qualcosa di orribile come questo:

enum { VOID_INT, VOID_INT_DOUBLE, VOID_DOUBLE_INT, ... } Signature;

void do_call(const void *userfunction, const void *args, Signature sig)
{
  switch(signature)
  {
    case VOID_INT:
    {
      int x = *(int *) args;
      void (*f)(int) = userfunction;
      f(x);
      break;
    }
    case VOID_INT_DOUBLE:
    ...
  }
}

Ma è abbastanza chiaro che questo non vive nello stesso continente, come la scalabilità. Si potrebbe, naturalmente, generare automaticamente il codice, per qualche ragionevole insieme di tipi di ritorno e tipi di argomenti. Saresti ancora un po 'fuori al freddo per la fusione puntatori a funzione da / per void *, ma che potrebbe essere accettabile. Farebbe ancora sempre corre il rischio che qualcuno si consegna una firma che non si dispone di codice pre-generato per, però.

Altri suggerimenti

libffi . Questa libreria permette di chiamare la funzione con un set di parametri specificati in fase di esecuzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top