development

C ++에서 런타임 동안 동적으로 함수를 만들 수 있습니까?

big-blog 2021. 1. 10. 19:49
반응형

C ++에서 런타임 동안 동적으로 함수를 만들 수 있습니까?


C ++는 정적이고 컴파일 된 언어이며 템플릿은 컴파일 시간 동안 확인됩니다.

그러나 런타임 중에 소스 코드에 설명되어 있지 않고 컴파일 중에 기계 언어로 변환되지 않은 함수를 생성하여 사용자가 소스에서 예상하지 못한 데이터를 던질 수 있도록 할 수 있습니까?

나는 이것이 간단한 방식으로 일어날 수 없다는 것을 알고 있지만, 확실히 가능해야합니다. 컴파일되지 않은 프로그래밍 언어가 많이 있고 C 또는 C ++로 구현되는 그런 종류의 것을 동적으로 생성합니다.

모든 기본 유형에 대한 팩토리가 적절한 데이터 구조와 함께 생성되어 사용자 유형 및 함수와 같은 더 복잡한 개체로 구성되는 경우 이것이 가능할까요?

주제에 대한 모든 정보와 온라인 자료에 대한 포인터를 환영합니다. 감사!

편집 : 가능하다는 것을 알고 있으며 구현 세부 사항에 관심이있는 것 같습니다. :)


, 물론 다른 답변에 언급 된 도구가 없지만 단순히 C ++ 컴파일러를 사용합니다 .

C ++ 프로그램 내에서 다음 단계를 따르십시오 (리눅스에서는 있지만 다른 OS에서도 유사해야 함).

  1. 다음을 사용하여 C ++ 프로그램을 파일 (예 : /tmp/prog.cc)에 작성합니다. ofstream
  2. 다음을 통해 프로그램을 컴파일하십시오. system("c++ /tmp/prog.cc -o /tmp/prog.so -shared -fPIC");
  3. 프로그램을 동적으로로드합니다. dlopen()

또한 바이트 코드를 함수에 직접 제공하고 아래에 설명 된대로 함수 유형으로 캐스팅 된 상태로 전달할 수도 있습니다.

예 :

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

예, JIT 컴파일러는 항상이를 수행합니다. 그들은 OS에 의해 특별한 실행 권한을 부여받은 메모리 조각을 할당 한 다음 코드로 채우고 포인터를 함수 포인터로 캐스팅하고 실행합니다. 아주 간단합니다.

편집 : 다음은 Linux에서 수행하는 방법에 대한 예입니다. http://burnttoys.blogspot.de/2011/04/how-to-allocate-executable-memory-on.html


C ++ 런타임 방법은 앞서 언급에 따라 컴파일 (출력 파일에 코드를 작성, 컴파일을 통해 대한 예를 아래에 system(), 부하를 통해 dlopen()하고 dlsym()). 관련 질문 의 예를 참조하십시오 . 여기서 차이점은 함수가 아닌 클래스를 동적으로 컴파일한다는 것입니다. 이는 maker()동적으로 컴파일 될 코드에 C 스타일 함수를 추가하여 수행됩니다 . 참조 :

이 예제는 Linux에서만 작동 LoadLibrary하며 (Windows에는 GetProcAddress대신 기능이 있음) 대상 컴퓨터에서 동일한 컴파일러를 사용할 수 있어야합니다.

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://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;
}

산출

$ 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

단순히 임베디드 스크립팅 언어 ( Lua 는 임베딩에 적합)를 사용하거나 런타임에 사용할 C ++ 용 컴파일러를 직접 작성 하는 것 외에도 C ++를 정말로 사용하려는 경우 기존 컴파일러를 사용할 수 있습니다.

For example Clang is 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 LLVM compiler 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.


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:

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++.

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.

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


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".

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/

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


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

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


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


Have a look into ExpressionTrees in .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.

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


You could take a look at Runtime Compiled C++ (or see RCC++ blog and videos), or perhaps try one of its alternatives.


It worked for me like this. You have to use the -fpermissive flag. I am using CodeBlocks 17.12.

#include <cstddef>

using namespace std;
int main()
{
    char func[] = {'\x90', '\x0f', '\x1'};
    void (*func2)() = reinterpret_cast<void*>(&func);
    func2();
    return 0;
}

성능을 원하지 않는 경우 사용 가능한 가장 간단한 솔루션은 Lua 또는 Python 과 같은 스크립팅 언어 인터프리터를 포함하는 것 입니다.

참조 URL : https://stackoverflow.com/questions/11016078/is-it-possible-to-create-a-function-dynamically-during-runtime-in-c

반응형