una todas tipos llamar lenguaje las funciones funcion estructura ejemplos declara como codigos c++ function dynamic runtime

c++ - todas - tipos de funciones en lenguaje c



¿Es posible crear una función de forma dinámica, durante el tiempo de ejecución en C++? (12)

Además de simplemente usar un lenguaje de scripts incrustado ( Lua es ideal para la incrustación) o escribir tu propio compilador para C ++ para usar en tiempo de ejecución, si realmente quieres usar C ++ puedes usar un compilador existente.

Por ejemplo, Clang es un compilador de C ++ creado como bibliotecas que podrían incorporarse fácilmente en otro programa. Fue diseñado para ser utilizado desde programas como IDE que necesitan analizar y manipular la fuente de C ++ de varias maneras, pero al usar la infraestructura de compilación LLVM como un backend, también tiene la capacidad de generar código en tiempo de ejecución y proporcionarle un puntero de función que pueda llamar para ejecutar el código generado.

C ++ es un lenguaje estático y compilado, las plantillas se resuelven durante el tiempo de compilación, etc.

Pero, ¿es posible crear una función durante el tiempo de ejecución, que no se describe en el código fuente y no se ha convertido al lenguaje de máquina durante la compilación, de modo que un usuario puede arrojar datos que no se han anticipado en la fuente?

Soy consciente de que esto no puede suceder de manera directa, pero seguramente debe ser posible, existen muchos lenguajes de programación que no se compilan y crean dinámicamente ese tipo de cosas que se implementan en C o C ++.

Tal vez si se crean fábricas para todos los tipos primitivos, junto con estructuras de datos adecuadas para organizarlos en objetos más complejos, como tipos de usuario y funciones, ¿se puede lograr esto?

Cualquier información sobre el tema, así como punteros a los materiales en línea son bienvenidos. ¡Gracias!

EDITAR: Soy consciente de que es posible, es más como que estoy interesado en los detalles de implementación :)


Básicamente necesitarás escribir un compilador C ++ dentro de tu programa (no es una tarea trivial), y hacer lo mismo que hacen los compiladores JIT para ejecutar el código. Estuviste en realidad el 90% del camino con este párrafo:

Soy consciente de que esto no puede suceder de manera directa, pero seguramente debe ser posible, existen muchos lenguajes de programación que no se compilan y crean dinámicamente ese tipo de cosas que se implementan en C o C ++.

Exactamente: esos programas llevan consigo el intérprete. Ejecuta un programa python diciendo python MyProgram.py --python es el código compilado C que tiene la capacidad de interpretar y ejecutar su programa sobre la marcha. Necesitaría hacer algo en esa línea, pero usando un compilador de C ++.

Si necesita funciones dinámicas, use un idioma diferente :)


Debajo hay un ejemplo de compilación en tiempo de ejecución de C ++ basada en el método mencionado anteriormente (escribir código en el archivo de salida, compilar a través del system() , cargar a través de dlopen() y dlsym() ). Ver también el ejemplo en una pregunta relacionada . La diferencia aquí es que compila dinámicamente una clase en lugar de una función. Esto se logra agregando una función maker() estilo C al código que se compilará dinámicamente. Referencias

El ejemplo solo funciona en Linux (Windows tiene funciones LoadLibrary y GetProcAddress lugar) y requiere que el compilador idéntico esté disponible en la máquina de destino.

baseclass.h

#ifndef BASECLASS_H #define BASECLASS_H class A { protected: double m_input; // or use a pointer to a larger input object public: virtual double f(double x) const = 0; void init(double input) { m_input=input; } virtual ~A() {}; }; #endif /* BASECLASS_H */

main.cpp

#include "baseclass.h" #include <cstdlib> // EXIT_FAILURE, etc #include <string> #include <iostream> #include <fstream> #include <dlfcn.h> // dynamic library loading, dlopen() etc #include <memory> // std::shared_ptr // compile code, instantiate class and return pointer to base class // https://www.linuxjournal.com/article/3687 // http://www.tldp.org/HOWTO/C++-dlopen/thesolution.html // https://.com/questions/11016078/ // https://.com/questions/10564670/ std::shared_ptr<A> compile(const std::string& code) { // temporary cpp/library output files std::string outpath="/tmp"; std::string headerfile="baseclass.h"; std::string cppfile=outpath+"/runtimecode.cpp"; std::string libfile=outpath+"/runtimecode.so"; std::string logfile=outpath+"/runtimecode.log"; std::ofstream out(cppfile.c_str(), std::ofstream::out); // copy required header file to outpath std::string cp_cmd="cp " + headerfile + " " + outpath; system(cp_cmd.c_str()); // add necessary header to the code std::string newcode = "#include /"" + headerfile + "/"/n/n" + code + "/n/n" "extern /"C/" {/n" "A* maker()/n" "{/n" " return (A*) new B(); /n" "}/n" "} // extern C/n"; // output code to file if(out.bad()) { std::cout << "cannot open " << cppfile << std::endl; exit(EXIT_FAILURE); } out << newcode; out.flush(); out.close(); // compile the code std::string cmd = "g++ -Wall -Wextra " + cppfile + " -o " + libfile + " -O2 -shared -fPIC &> " + logfile; int ret = system(cmd.c_str()); if(WEXITSTATUS(ret) != EXIT_SUCCESS) { std::cout << "compilation failed, see " << logfile << std::endl; exit(EXIT_FAILURE); } // load dynamic library void* dynlib = dlopen (libfile.c_str(), RTLD_LAZY); if(!dynlib) { std::cerr << "error loading library:/n" << dlerror() << std::endl; exit(EXIT_FAILURE); } // loading symbol from library and assign to pointer // (to be cast to function pointer later) void* create = dlsym(dynlib, "maker"); const char* dlsym_error=dlerror(); if(dlsym_error != NULL) { std::cerr << "error loading symbol:/n" << dlsym_error << std::endl; exit(EXIT_FAILURE); } // execute "create" function // (casting to function pointer first) // https://.com/questions/8245880/ A* a = reinterpret_cast<A*(*)()> (create)(); // cannot close dynamic lib here, because all functions of the class // object will still refer to the library code // dlclose(dynlib); return std::shared_ptr<A>(a); } int main(int argc, char** argv) { double input=2.0; double x=5.1; // code to be compiled at run-time // class needs to be called B and derived from A std::string code = "class B : public A {/n" " double f(double x) const /n" " {/n" " return m_input*x;/n" " }/n" "};"; std::cout << "compiling.." << std::endl; std::shared_ptr<A> a = compile(code); a->init(input); std::cout << "f(" << x << ") = " << a->f(x) << std::endl; return EXIT_SUCCESS; }

salida

$ g++ -Wall -std=c++11 -O2 -c main.cpp -o main.o # c++11 required for std::shared_ptr $ g++ -ldl main.o -o main $ ./main compiling.. f(5.1) = 10.2


Echa un vistazo a libtcc ; es simple, rápido, confiable y se adapta a sus necesidades. Lo uso cada vez que necesito compilar funciones C "sobre la marcha".

En el archivo, encontrará el archivo examples / libtcc_test.c , que puede darle una buena ventaja. Este pequeño tutorial también podría ayudarlo: http://blog.mister-muffin.de/2011/10/22/discovering-tcc/

¡Haga preguntas en los comentarios si encuentra algún problema al usar la biblioteca!


Eche un vistazo a ExpressionTrees en .NET: creo que esto es básicamente lo que quiere lograr. Crea un árbol de subexpresiones y luego evalúalas. De forma orientada a objetos, cada nodo en el podría saber cómo evaluarse a sí mismo, por recursión en sus subnodos. Su lenguaje visual entonces crearía este árbol y usted puede escribir un intérprete simple para ejecutarlo.

Además, echa un vistazo a Ptolemy II , como ejemplo en Java sobre cómo se puede escribir un lenguaje de programación visual.


La solución más simple disponible, si no busca rendimiento, es incorporar un intérprete de lenguaje de scripts, por ejemplo, para Lua o Python .



Sí, los compiladores de JIT lo hacen todo el tiempo. Asignan una pieza de memoria a la que el SO le ha otorgado derechos de ejecución especiales, luego la rellena con un código y arroja el puntero a un puntero de función y lo ejecuta. Bastante simple.

EDITAR: Aquí hay un ejemplo de cómo hacerlo en Linux: http://burnttoys.blogspot.de/2011/04/how-to-allocate-executable-memory-on.html


Sí, puedes escribir un compilador para C ++, en C ++, con algunas características adicionales, escribir tus propias funciones, compilar y ejecutar automáticamente (o no) ...


También puede simplemente dar el bytecode directamente a una función y simplemente pasarlo fundido como el tipo de función como se muestra a continuación.

p.ej

byte[3] func = { 0x90, 0x0f, 0x1 } *reinterpret_cast<void**>(&func)()


Un enfoque típico para esto es combinar un proyecto de C ++ (o lo que sea que esté escrito) con lenguaje de scripting.
Lua es uno de los principales favoritos, ya que está bien documentado, es pequeño y tiene enlaces para muchos idiomas.

Pero si no está mirando en esa dirección, ¿tal vez podría pensar en hacer uso de las bibliotecas dinámicas?


, por supuesto, sin ninguna herramienta mencionada en las otras respuestas, pero simplemente usando el compilador de C ++ .

simplemente siga estos pasos desde dentro de su programa C ++ (en Linux, pero debe ser similar en otros sistemas operativos)

  1. escribe un programa C ++ en un archivo (por ejemplo, en /tmp/prog.cc), usando un ofstream
  2. compilar el programa a través del system("c++ /tmp/prog.cc -o /tmp/prog.so -shared -fPIC");
  3. cargar el programa dinámicamente, por ejemplo, usando dlopen()