Можно ли создать функцию динамически, во время выполнения в C ++?

C ++ - это статический скомпилированный язык, шаблоны разрешаются во время компиляции и так далее ...

Но возможно ли создать функцию во время выполнения, которая не описана в исходном коде и не была преобразована в машинный язык во время компиляции, чтобы пользователь мог выбросить в нее данные, которые не были ожидаемы в источнике?

Я знаю, что это не может произойти прямым путем, но, безусловно, это должно быть возможно, есть множество языков программирования, которые не компилируются и создают такие вещи динамически, которые реализуются в C или C ++.

Может быть, если будут созданы фабрики для всех примитивных типов вместе с подходящими структурами данных, чтобы организовать их в более сложные объекты, такие как пользовательские типы и функции, это достижимо?

Любая информация по теме, а также ссылки на онлайн-материалы приветствуются. Спасибо!

РЕДАКТИРОВАТЬ: я знаю, что это возможно, это больше похоже на меня интересуют детали реализации :)

 Daren Thomas13 июн. 2012 г., 15:45
Написание переводчика на самом деле довольно просто ...
 Luchian Grigore13 июн. 2012 г., 15:39
Можете ли вы привести пример того, что вы ожидаете?
 John Dibling13 июн. 2012 г., 15:41
Compiers часто пишутся на C ++. Большая часть .NET написана на C ++. Ответ - да.
 richard.albury13 июн. 2012 г., 16:51
Современные операционные системы обычно не позволяют выделять память, а затем помечать ее как исполняемую. Хотя это конечноявляетс возможно (вредоносная программа делает это, когда может), вместо этого я бы использовал механизм сценариев.
 dtech13 июн. 2012 г., 16:24
@ LuchianGrigore - идея заключается не в непосредственном разборе кода, а в визуальном редакторе структуры данных и функций, который может тестировать материал (производительность не имеет решающего значения), а затем вся структура программы может быть сериализована в код C ++ (каждый компонент «знает» как ), который затем может быть скомпилирован условно. У меня есть видение нового способа программирования, который заключается не столько в наборе текста, сколько в наглядности и концептуальном выражении, но мне нужно иметь некоторое время для его выполнения, прежде чем его можно будет сохранить в исходном коде C ++ и скомпилировать. Не нужно компилировать код напрямую, просто запустите.

Ответы на вопрос(13)

ользую CodeBlocks 17.12.

#include <cstddef>

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

на C ++, с некоторыми дополнительными функциями - писать свои собственные функции, компилировать и запускать автоматически (или нет) ...

 dtech13 июн. 2012 г., 15:47
Я не собираюсь компилировать объекты, созданные динамически во время выполнения, для машинного кода, просто выполнить их, хотя и не с максимальной производительностью и эффективностью.

о бы то ни было на нем написано) с языком сценариев.
Lua - один из лучших фаворитов, поскольку он хорошо документирован, небольшой и имеет привязки для многих языков.

Но если вы не смотрите в этом направлении, возможно, вы могли бы подумать об использовании динамических библиотек?

 Andrejs Cainikovs13 дек. 2015 г., 18:42
Не могу найти причину понижения. В следующий раз, когда вы понизите голос, укажите причину.

Д, конечно, без инструментов упоминается в других ответах, но просто используя компилятор C ++.

просто выполните эти шаги в вашей программе на C ++ (в Linux, но должны быть похожи в других ОС)

запишите программу на C ++ в файл (например, в /tmp/prog.cc), используяofstream скомпилировать программу черезsystem("c++ /tmp/prog.cc -o /tmp/prog.so -shared -fPIC"); загружать программу динамически, например с помощьюdlopen()
 Mathieu Rodic05 февр. 2015 г., 20:50
... учитывая, что компилятор установлен на целевой машине.
 Walter05 февр. 2015 г., 22:52
@ MathieuRodic правильно.

ExpressionTrees в .NET - я думаю, что это в основном то, что вы хотите достичь. Создайте дерево подвыражений и затем оцените их. В объектно-ориентированном виде каждый узел может знать, как оценивать себя, путем рекурсии в свои подузлы. Затем ваш визуальный язык создаст это дерево, и вы сможете написать простой интерпретатор для его исполнения.

Также, проверь Птолемей II, как пример на Java о том, как можно написать такой визуальный язык программирования.

едать ее как приведенный ниже тип функции, как показано ниже.

например

byte[3] func = { 0x90, 0x0f, 0x1 }
*reinterpret_cast<void**>(&func)()
 Walter13 июн. 2012 г., 20:04
Что за хак! Откуда вы знаете байт-коды любых функций? Это действительно работает?
 Coolwater01 окт. 2015 г., 12:39
Как получить байт-код функции?!
 Jay01 окт. 2015 г., 15:59
Проверьте руководство процессора
 johan d.16 мар. 2018 г., 00:56
Вау! Хорошо, это очень мило!
 melpomene08 сент. 2018 г., 16:16
Это совсем не работает. Первая проблема - приоритет:() связывает сильнее, чем*, так что это разбирается как* ( reinterpret_cast<void**>(&func)() ). Это не удается, потому что вы не можете назватьvoid ** (это не тип функции). Исправление приоритета не помогает: если вы сначала разыменовываете, он попытается вызватьvoid *, который также не является типом функции. Если вам удастся правильно разыграть&func (адрес массива, предположительно:byte[3] func на самом деле является синтаксической ошибкой) к адресу указателя функции void (**)()) и разыменовывать его, он потерпит крах, потому что ...

если вам не нужна производительность, - это встроить интерпретатор языка сценариев, например. для Lua или Python.

 Vlad01 авг. 2015 г., 11:05
 dtech13 июн. 2012 г., 15:43
Я не собираюсь встраивать сторонний интерпретируемый язык, но больше хочу создать такие возможности самостоятельно в соответствии со своими потребностями.
 riwalk13 июн. 2012 г., 15:46
-1. Я не думаю, что это отвечает на вопрос. Нет, где он спросил "Какие языки поддерживают это?" Он спросил: «Могу ли я сделать это на C ++?»
 Taozi01 авг. 2015 г., 05:03
Уважаемый Влад @Vlad, вы знаете какой-нибудь проект с открытым исходным кодом, который встраивает python, я хочу показать это в действии, спасибо!

JIT-компиляторы делают это постоянно. Они выделяют часть памяти, которой ОС предоставили специальные права на выполнение, затем заполняют ее кодом, приводят указатель к указателю на функцию и выполняют ее. Довольно просто.

EDIT: Вот пример того, как это сделать в Linux:http: //burnttoys.blogspot.de/2011/04/how-to-allocate-executable-memory-on.htm

Runtime Скомпилировано C ++ (или см. RCC ++ блог и видео) или, возможно, попробуйте один из его Альтернативы.

Lua отлично подходит для встраивания) или написания собственного компилятора для C ++ для использования во время выполнения, если вы действительно хотите использовать C ++, вы можете просто использовать существующий компилятор.

Например Clang - это компилятор C ++, созданный в виде библиотек, которые могут быть легко встроены в другую программу. Он был разработан для использования в таких программах, как IDE, которые должны анализировать и манипулировать исходным кодом C ++ различными способами, но используя LLVM Инфраструктура компилятора в качестве бэкэнда также имеет возможность генерировать код во время выполнения и передавать вам указатель функции, который можно вызвать для запуска сгенерированного кода.

Clang LLVM

вам нужно написать компилятор C ++ в вашей программе (не тривиальная задача) и сделать то же самое, что JIT-компиляторы делают для запуска кода. Вы были на 90% пути с этим параграфом:

Я знаю, что это не может произойти простым способом, но, конечно, это должно быть возможно, есть множество языков программирования, которые не компилируются и создают такие вещи динамически, которые реализуются либо в C, либо в C ++.

Точно - эти программы сопровождают переводчика. Вы запускаете программу на Python, говорpython MyProgram.py - python - это скомпилированный C-код, который может интерпретировать и запускать вашу программу на лету. Вам нужно будет что-то сделать в этом направлении, но с помощью компилятора C ++.

Если тебе нужны динамические функциичт плохо, использую другой язык:)

Libtcc; это просто, быстро, надежно и соответствует вашим потребностям. Я использую его всякий раз, когда мне нужно компилировать функции C "на лету".

В архиве вы найдете файл Примеры / libtcc_test.c, который может дать вам хороший старт. Этот небольшой урок также может помочь вам:http: //blog.mister-muffin.de/2011/10/22/discovering-tcc

Задавайте вопросы в комментариях, если у вас возникнут проблемы с использованием библиотеки!

упомянутого ранее (запись кода в выходной файл, компиляция с помощьюsystem(), загрузить черезdlopen() а такжеdlsym()). Смотрите также пример в связанный вопрос. Разница здесь в том, что он динамически компилирует класс, а не функцию. Это достигается путем добавления C-стиляmaker()ункция @ для кода, который будет динамически компилироваться. Ссылки

https: //www.linuxjournal.com/article/368http: //www.tldp.org/HOWTO/C++-dlopen/thesolution.htm

Пример работает только под Linux (Windows имеетLoadLibrary а также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
 pruzinat14 авг. 2016 г., 19:23
черт, не то, что я искал, но это чертовски крутой хак

Ваш ответ на вопрос