是否可以在 C++ 运行时动态创建函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11016078/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:45:05  来源:igfitidea点击:

Is it possible to create a function dynamically, during runtime in C++?

c++functiondynamicruntime

提问by dtech

C++ is a static, compiled language, templates are resolved during compile time and so on...

C++ 是一种静态的编译语言,在编译时解析模板等等...

But is it possible to create a function during runtime, that is not described in the source code and has not been converted to machine language during compilation, so that a user can throw at it data that has not been anticipated in the source?

但是是否有可能在运行时创建一个源代码中未描述且在编译期间未转换为机器语言的函数,以便用户可以将源中未预料到的数据扔给它?

I am aware this cannot happen in a straightforward way, but surely it must be possible, there are plenty of programing languages that are not compiled and create that sort of stuff dynamically that are implemented in either C or C++.

我知道这不能以一种直接的方式发生,但肯定是可能的,有很多编程语言没有被编译,并动态地创建那种用 C 或 C++ 实现的东西。

Maybe if factories for all primitive types are created, along with suitable data structures to organize them into more complex objects such as user types and functions, this is achievable?

也许如果创建所有原始类型的工厂,以及合适的数据结构将它们组织成更复杂的对象,例如用户类型和函数,这是可以实现的吗?

Any info on the subject as well as pointers to online materials are welcome. Thanks!

欢迎提供有关该主题的任何信息以及指向在线材料的指针。谢谢!

EDIT: I am aware it is possible, it is more like I am interested in implementation details :)

编辑:我知道这是可能的,更像是我对实现细节感兴趣:)

回答by Walter

Yes, of course, without any toolsmentioned in the other answers, but simply using the C++ compiler.

是的,当然,没有在其他答案中提到任何工具,而只是使用 C++ 编译器

just follow these steps from within your C++ program (on linux, but must be similar on other OS)

只需在您的 C++ 程序中执行这些步骤(在 linux 上,但在其他操作系统上必须类似)

  1. write a C++ program into a file (e.g. in /tmp/prog.cc), using an ofstream
  2. compile the program via system("c++ /tmp/prog.cc -o /tmp/prog.so -shared -fPIC");
  3. load the program dynamically, e.g. using dlopen()
  1. 将 C++ 程序写入文件(例如在 /tmp/prog.cc 中),使用 ofstream
  2. 通过编译程序 system("c++ /tmp/prog.cc -o /tmp/prog.so -shared -fPIC");
  3. 动态加载程序,例如使用 dlopen()

回答by Jay

You can also just give the bytecode directly to a function and just pass it casted as the function type as demonstrated below.

您也可以将字节码直接提供给函数,然后将其作为函数类型传递,如下所示。

e.g.

例如

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

回答by Milan

Yes, JIT compilers do it all the time. They allocate a piece of memory that has been given special execution rights by the OS, then fill it with code and cast the pointer to a function pointer and execute it. Pretty simple.

是的,JIT 编译器一直在做。他们分配一块被操作系统赋予特殊执行权限的内存,然后用代码填充它并将指针转换为函数指针并执行它。很简单。

EDIT: Here's an example on how to do it in Linux: http://burnttoys.blogspot.de/2011/04/how-to-allocate-executable-memory-on.html

编辑:这是一个关于如何在 Linux 中执行此操作的示例:http: //burnttoys.blogspot.de/2011/04/how-to-allocate-executable-memory-on.html

回答by user1059432

Below an example for C++ runtime compilation based on the method mentioned before (write code to output file, compile via system(), load via dlopen()and dlsym()). See also the example in a related question. The difference here is that it dynamically compiles a class rather than a function. This is achieved by adding a C-style maker()function to the code to be compiled dynamically. References:

下面是一个基于前面提到的方法的 C++ 运行时编译示例(将代码写入输出文件,编译通过system(),加载通过dlopen()dlsym())。另请参阅相关问题中的示例。这里的区别在于它动态编译一个类而不是一个函数。这是通过maker()向要动态编译的代码添加 C 样式函数来实现的。参考:

The example only works under Linux (Windows has LoadLibraryand GetProcAddressfunctions instead), and requires the identical compiler to be available on the target machine.

该示例仅适用于 Linux(Windows 具有LoadLibraryGetProcAddress函数),并且需要在目标机器上使用相同的编译器。

baseclass.h

基类.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://stackoverflow.com/questions/11016078/
// https://stackoverflow.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://stackoverflow.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;
}

output

输出

$ 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

回答by bames53

In addition to simply using an embedded scripting language (Luais great for embedding) or writing your own compiler for C++ to use at runtime, if you really want to use C++ you can just use an existing compiler.

除了简单地使用嵌入式脚本语言(Lua非常适合嵌入)或为 C++ 编写自己的编译器以在运行时使用,如果你真的想使用 C++,你可以只使用现有的编译器。

For example Clangis a C++ compiler built as libraries that could be easily embedded in another program. It was designed to be used from programs like IDEs that need to analyze and manipulate C++ source in various ways, but using the LLVMcompiler infrasructure as a backend it also has the ability to generate code at runtime and hand you a function pointer that you can call to run the generated code.

例如,Clang是一个 C++ 编译器,它构建为可以轻松嵌入到另一个程序中的库。它被设计用于需要以各种方式分析和操作 C++ 源代码的 IDE 等程序,但使用LLVM编译器基础架构作为后端,它还能够在运行时生成代码并向您提供一个函数指针,您可以调用以运行生成的代码。

回答by riwalk

Essentially you will need to write a C++ compiler within your program (not a trivial task), and do the same thing JIT compilers do to run the code. You were actually 90% of the way there with this paragraph:

本质上,您需要在程序中编写 C++ 编译器(不是一项微不足道的任务),并执行 JIT 编译器为运行代码所做的相同操作。您实际上已经完成了这一段的 90%:

I am aware this cannot happen in a straightforward way, but surely it must be possible, there are plenty of programing languages that are not compiled and create that sort of stuff dynamically that are implemented in either C or C++.

我知道这不能以一种直接的方式发生,但肯定是可能的,有很多编程语言没有被编译,并动态地创建那种用 C 或 C++ 实现的东西。

Exactly--those programs carry the interpreter with them. You run a python program by saying python MyProgram.py--python is the compiled C code that has the ability to interpret and run your program on the fly. You would need do something along those lines, but by using a C++ compiler.

正是——这些程序带有解释器。您可以通过说python MyProgram.py--python 是编译后的 C 代码来运行 python 程序,它能够即时解释和运行您的程序。您需要按照这些方式做一些事情,但要使用 C++ 编译器。

If you need dynamic functions thatbadly, use a different language :)

如果你需要动态的功能厉害,使用不同的语言:)

回答by Mathieu Rodic

Have a look at libtcc; it is simple, fast, reliable and suits your need. I use it whenever I need to compile C functions "on the fly".

看看libtcc;它简单、快速、可靠并且适合您的需要。每当我需要“即时”编译 C 函数时,我都会使用它。

In the archive, you will find the file examples/libtcc_test.c, which can give you a good head start. This little tutorial might also help you: http://blog.mister-muffin.de/2011/10/22/discovering-tcc/

在存档中,您将找到文件examples/libtcc_test.c,它可以为您提供良好的开端。这个小教程也可能对您有所帮助:http: //blog.mister-muffin.de/2011/10/22/discovering-tcc/

Ask questions in the comments if you meet any problems using the library!

如果您在使用图书馆时遇到任何问题,请在评论中提出问题!

回答by Andrejs Cainikovs

A typical approach for this is to combine a C++ (or whatever it's written on) project with scripting language.
Luais one of the top favorites, since it's well documented, small, and has bindings for a lot of languages.

一个典型的方法是将 C++(或任何它编写的)项目与脚本语言结合起来。
Lua是最受欢迎的语言之一,因为它有据可查、体积小,并且绑定了多种语言。

But if you are not looking into that direction, perhaps you could think of making a use of dynamic libraries?

但是,如果您不朝那个方向看,也许您可​​以考虑使用动态库?

回答by Luchian Grigore

Yes - you can write a compiler for C++, in C++, with some extra features - write your own functions, compile and run automatically (or not)...

是的 - 你可以用 C++ 为 C++ 编写一个编译器,带有一些额外的功能 - 编写你自己的函数,自动编译和运行(或不自动运行)......

回答by Daren Thomas

Have a look into ExpressionTreesin .NET - I think this is basically what you want to achieve. Create a tree of subexpressions and then evaluate them. In an object-oriented fashion, each node in the might know how to evaluate itself, by recursion into its subnodes. Your visual language would then create this tree and you can write a simple interpreter to execute it.

看看ExpressionTrees.NET - 我认为这基本上是你想要实现的。创建一个子表达式树,然后评估它们。在面向对象的方式中,节点中的每个节点都可能知道如何通过递归到其子节点来评估自己。然后您的视觉语言将创建这棵树,您可以编写一个简单的解释器来执行它。

Also, check out Ptolemy II, as an example in Java on how such a visual programming language can be written.

另外,请查看Ptolemy II,作为 Java 中如何编写这种可视化编程语言的示例。