Estoy tratando de usar la función de esa entrada (del archivo), por sus nombres.

Por ejemplo: en el archivo que escribí

     functionOne(1,2)

Logré separar el nombre de la función y sus argumentos en una matriz diferente; ahora tengo:

    funcName[] = functioOne
    funcArg[0] = 1
    funcArg[1] = 2

Pero ahora me quedé atrapado, ¿cómo puedo usarlo? Traté de hacer una serie de punteros a las funciones, pero no tengo idea de cómo usarlo. ¿Cualquier sugerencia? Gracias

c
0
puhs 20 ene. 2018 a las 18:01

3 respuestas

La mejor respuesta

C no tiene introspección . No es posible, durante el tiempo de ejecución, obtener o llamar a una función desde una cadena.

Sin embargo, hay soluciones alternativas. Por ejemplo, puede crear una tabla que contenga el nombre de la función y un puntero a la función. Luego puede buscar en esta tabla para encontrar la función a la que llamar.

Quizás algo como

void functionOne(int arg1, int arg2)
{
    ...
}

struct
{
    char *name;
    void (*function)(int, int);
} functions[] = {
    { "funcitonOne", &functionOne },
};

Para hacerlo más genérico, cuando tiene muchas funciones que toman diferentes cantidades de argumentos, es un poco más difícil. Luego, en lugar de pasar argumentos como lo normal, puede pasar una matriz que contiene los argumentos:

void functionOne(int *arguments)
{
    // arguments[0] is the first arguments, etc.
    ...
}

Modifique el puntero de función en la estructura en consecuencia.

Si los tipos de argumentos también difieren, podría usar estructuras con una etiqueta de tipo y una unión para los valores.

3
Some programmer dude 20 ene. 2018 a las 15:07

No puede hacer lo que quiere en C. Lo más cercano que puede hacer es mantener una matriz de punteros de función que apuntará hacia las funciones respectivas. También mantenga una matriz de cadenas que sea exactamente según el mismo índice que la de otra matriz. Ahora, siempre que obtenga el nombre de una función, simplemente analícela, compare y obtenga el puntero de función apropiado según el índice de la cadena coincidente.

Cómo enviar los argumentos: bueno, para hacerlo, diría que hace esto, cuando sepa a qué función tendrá que llamar, analizará los argumentos desde el archivo mismo (sabrá que esta función tomará 2 argumentos, así que obtendrá la línea y la analizará a int y double como se espera y luego la llamará en consecuencia).

2
user2736738 20 ene. 2018 a las 15:35

En general, no puede hacer lo que quiere en portable C11 (lea n1570), como lo explicaron otros: los nombres de funciones son una cosa en tiempo de compilación y son desconocidos en el momento de la ejecución. El lenguaje de programación C no tiene reflexión y / o introspección. Por cierto, una función podría incluso "desaparecer" durante compilación optimizada (así que "prácticamente" existen en tiempo de ejecución, pero su programa se comporta como-si esa función existe), en el sentir que ha sido en línea o eliminado de ejecutable. Sin embargo, C tiene punteros de función (cuyo tipo describe la firma de la función llamada indirectamente); Hablando prácticamente, apuntan a código de máquina.


Pero si codifica un programa de aplicación en una x86-64 computadora que se ejecuta, p. Linux, es posible que a veces tenga algunas soluciones alternativas, usando algunos trucos "sucios", específicos para eso sistema operativo y arquitectura del conjunto de instrucciones:

  • dada alguna cadena como "functionOne" (prácticamente, del tipo const char*), podría obtener un puntero de función (por ejemplo, functionOne, siempre que tenga < a href = "https://en.wikipedia.org/wiki/Linkage_(software)" rel = "nofollow noreferrer"> enlace ) -por medio de enlaces dinámicos- utilizando dlopen (3) con una ruta NULL, luego dlsym (3). Por cierto, la asignación inversa (de direcciones a nombres) está disponible a través de dladdr (3 ).

  • dado un puntero de función (o en realidad cualquier dirección válida en su < a href = "https://en.wikipedia.org/wiki/Virtual_address_space" rel = "nofollow noreferrer"> espacio de direcciones virtuales apuntando dentro de algún ejecutable segmento de código), podría llamarlo indirectamente si se conoce la firma de esa función en tiempo de compilación (se proporciona en el tipo de ese puntero de función).

  • si desea llamar a una función arbitraria con firma arbitraria y argumentos arbitrarios solo conocidos en tiempo de ejecución , puede usar el libffi. Conoce el ABI de su sistema.

  • un posible truco también es emitir algún archivo temporal /tmp/emittedcode.c que contenga código C (en tiempo de ejecución), bifurcar un proceso de compilación en un complemento temporal (por ejemplo, gcc -Wall -O -shared -fPIC/tmp/emittedcode.c -o /tmp/emittedplugin.so) y carga dinámicamente ese complemento temporal /tmp/emittedplugin.so con dlopen (3). Asegúrese de limpiar el desorden (por ejemplo, eliminar todos los archivos temporales, tal vez usando atexit (3)) al finalizar el programa.

  • quizás desee generar algún código de máquina en tiempo de ejecución; entonces considere también alguna compilación JIT como GCCJIT, LLVM, libjit, asmjit.

Si su PC no está ejecutando Linux, puede encontrar cosas equivalentes para su sistema operativo y computadora. Lea Sistemas operativos: tres piezas fáciles para aprender Más información sobre los sistemas operativos en general. Lea la documentación de su sistema operativo particular (para Linux, lea primero el ALP o algún libro más nuevo sobre programación Linux, luego introducción (2), syscalls (2), elf (5) y páginas relacionadas).


Por cierto, si solo desea llamar a funciones desde su programa (desde nombres en algún archivo de entrada), en su lugar, puede crear en la inicialización algunas tabla hash (o mapa, tal vez un árbol rojo-negro) asociando nombres de funciones a punteros de función, como se sugiere en esta otra respuesta.

Tal vez desee un homoiconic lenguaje de programación que tenga algún primitivo eval. Mira en Common Lisp. Tenga en cuenta que SBCL, se está compilando en un código de máquina generado dinámicamente como máximo REPL interacciones.

Tal vez esté escribiendo algún intérprete (que a menudo es más difícil y lento que usted piense, lea el Dragon Book). Considere quizás incrustar y usar uno existente, como Guile o Lua.

1
Basile Starynkevitch 20 ene. 2018 a las 17:26