Conjunto de funciones, nombres y argumentos.

Estoy tratando de usar la función de entrada (desde el 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 quedo atascado, ¿cómo puedo usarlo? Intenté hacer una serie de punteros a las funciones, pero no tengo idea de cómo usarlo. ¿Cualquier sugerencia? Gracias

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

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

Tal vez 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 tienes muchas funciones que toman diferentes argumentos, es un poco más difícil. Luego, en lugar de pasar argumentos como de costumbre, puede pasar una matriz que contenga los argumentos:

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

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

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

No puede hacer lo que quiere en C. Lo más cercano que puede hacer es mantener una serie de punteros de función que apuntarán hacia las funciones respectivas. También mantenga una matriz de cadenas que coincida exactamente con el mismo índice que el de otra matriz. Ahora, cada vez que obtiene un nombre de función, simplemente lo analiza, compara y obtiene el puntero de función adecuado en función del índice de la cadena coincidente.

Cómo enviar los argumentos, por lo que diría que va sobre esto: cuando sepa a qué función tendrá que llamar, analice los argumentos del archivo (sabrá que esta función tomará 2 argumentos). obtendrá la línea y la analizará en int y double como se espera y luego la llamará en consecuencia).

En general, no puede hacer lo que quiere en C11 portátil (lea n1570 ), como explican otros: los nombres de funciones son una cosa de tiempo de comstackción y son desconocidos en el momento de la ejecución. El lenguaje de progtwigción C no tiene reflexión y / o introspección . Por cierto, una función podría incluso “desaparecer” durante la comstackción optimizada (por lo que no existe “prácticamente” en tiempo de ejecución, pero su progtwig se comporta como si esa función existe), en el sentido de que se ha incorporado o eliminado del ejecutable . Sin embargo, C tiene punteros de función (cuyo tipo describe la firma de la función llamada indirectamente); En términos prácticos, apuntan al código de máquina .


Pero si codifica un progtwig de aplicación en una computadora x86-64 que ejecuta, por ejemplo, Linux, a veces puede tener algunas soluciones alternativas, utilizando algunos trucos “sucios”, específicos de ese sistema operativo y architecture de conjunto de instrucciones :

  • dada una cadena como "functionOne" (prácticamente, de tipo const char* ), puede obtener un puntero a la functionOne (por ejemplo, functionOne , siempre que tenga un enlace externo) -a través de las funciones de enlace dynamic- usando dlopen (3) con un NULL camino, entonces 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 espacio de dirección virtual que apunta dentro de un segmento de código ejecutable ), podría llamarlo indirectamente si la firma de esa función se conoce en el momento de la comstackción (aparece en el tipo de puntero de esa función ).

  • Si desea llamar a una función arbitraria con firma arbitraria y argumentos arbitrarios que solo se conocen en tiempo de ejecución , puede usar el libffi . Conoce el ABI de tu sistema.

  • Un posible truco también es emitir un archivo temporal /tmp/emittedcode.c contiene código C (en tiempo de ejecución), unir un proceso de comstackción a un complemento temporal (por ejemplo, gcc -Wall -O -shared -fPIC/tmp/emittedcode.c -o /tmp/emittedplugin.so ), y cargue dinámicamente ese complemento temporal /tmp/emittedplugin.so con dlopen (3) . Asegúrese de limpiar el desorden (p. Ej., Elimine todos los archivos temporales, quizás utilizando atexit (3) ) al finalizar el progtwig.

  • quizás desee generar algún código de máquina en tiempo de ejecución; Luego considere también alguna biblioteca de comstackció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 sencillas para obtener más información sobre los sistemas operativos en general. Lea la documentación de su sistema operativo en particular (para Linux, lea primero el ALP o algún libro más reciente sobre progtwigción en Linux, luego intro (2) , syscalls (2) , elf (5) y páginas relacionadas).


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

Tal vez quieras un lenguaje de progtwigción homoicónico que tenga algo de eval primitiva . Mira en Common Lisp. Sea consciente de SBCL , se está comstackndo en un código de máquina generado dinámicamente en la mayoría de las interacciones REPL .

Quizás esté escribiendo algún intérprete (que a menudo es más difícil y lleva más tiempo de lo que cree, lea el Libro del Dragón ). Considere la posibilidad de incrustar y usar uno existente, como Guile o Lua .