Pregunta

Tengo este programa en el que quiero que otros procesos puedan llamar funciones (a través de sockets Unix).El protocolo del mensaje es muy simple, el nombre de la función, una firma de la función y un búfer (char *) que contiene los parámetros.

Cuando un módulo de mi programa quiere permitir que se pueda acceder a una función, registra el nombre y la firma en la biblioteca.El problema al que me enfrento es llamar físicamente a la función una vez que llega la solicitud.He examinado bibliotecas similares a RPC y Java RMI, pero requieren que genere códigos auxiliares para ajustar las llamadas.El sistema en el que estoy trabajando es muy dinámico y también tengo que interactuar con el código de otras personas que no puedo modificar.

Básicamente, una función podría verse así:

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

ahora me registro en la biblioteca:

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

Cuando llega la solicitud, hago algunas comprobaciones de errores; una vez válida, quiero llamar a la función.Entonces tengo las variables:

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

¿Cómo puedo llamar a la función con los parámetros en C?

¡Gracias!

¿Fue útil?

Solución

No creo que esto se pueda resolver completamente en general, usando solo C.Por ejemplo, no conoce la convención de llamada utilizada por la función de destino.Existe el riesgo de que termines "engañando" al compilador, o al menos tengas que dudarlo.¿Qué pasaría si el compilador decidiera construir la función registrada usando argumentos pasados ​​en los registros, tal vez debido a alguna configuración de optimización (o qué pasaría si se compilara con un compilador diferente?).

En general, tampoco hay forma de expresar en C que desea llamar a una función con un conjunto determinado de argumentos y que los valores de los argumentos deben descomprimirse de un búfer de bytes aleatorios.

Podrías hacer algo horrible como esto:

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:
    ...
  }
}

Pero está bastante claro que esto no vive en el mismo continente que la escalabilidad.Por supuesto, podría generar automáticamente este código, para algún conjunto razonable de tipos de retorno y tipos de argumentos.Todavía estarías un poco fuera de lugar para enviar punteros de función hacia/desde void *, pero eso podría ser aceptable.Sin embargo, siempre correrás el riesgo de que alguien te entregue una firma para la que no tienes un código generado previamente.

Otros consejos

libffi . Esta biblioteca permite a llamar a la función con un conjunto de parámetros especificados en tiempo de ejecución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top