59

C++ は静的なコンパイル済み言語であり、テンプレートはコンパイル時に解決されます...

しかし、ソースコードに記述されておらず、コンパイル時に機械語に変換されていない関数を実行時に作成して、ユーザーがソースで予期されていないデータをスローできるようにすることは可能ですか?

これは簡単な方法では起こり得ないことは承知していますが、確かに可能であるに違いありません。コンパイルされておらず、C または C++ で実装されているようなものを動的に作成するプログラミング言語がたくさんあります。

おそらく、すべてのプリミティブ型のファクトリが作成され、それらをユーザー型や関数などのより複雑なオブジェクトに編成するための適切なデータ構造があれば、これは達成可能でしょうか?

この件に関する情報やオンライン資料へのポインタは大歓迎です。ありがとう!

編集:可能であることは承知しています。実装の詳細に興味があるようです:)

4

14 に答える 14

50

はい、もちろん、他の回答で言及されているツールはありませんが、単に C++ コンパイラを使用しています。

C++ プログラム内から次の手順に従ってください (Linux では、他の OS でも同様である必要があります)。

  1. C++ プログラムをファイル (例: /tmp/prog.cc) に書き込みます。ofstream
  2. 経由でプログラムをコンパイルしますsystem("c++ /tmp/prog.cc -o /tmp/prog.so -shared -fPIC");
  3. プログラムを動的にロードします。dlopen()
于 2012-06-13T13:53:46.543 に答える
41

以下に示すように、バイトコードを関数に直接渡して、関数型としてキャストして渡すこともできます。

例えば

byte[3] func = { 0x90, 0x0f, 0x1 }
*reinterpret_cast<void**>(&func)()
于 2012-06-13T17:36:33.247 に答える
20

はい、JIT コンパイラーは常にそれを行っています。OS によって特別な実行権限が与えられたメモリの一部を割り当て、そこにコードを入力し、ポインターを関数ポインターにキャストして実行します。ものすごく単純。

編集: Linux でそれを行う方法の例を次に示します: http://burnttoys.blogspot.de/2011/04/how-to-allocate-executable-memory-on.html

于 2012-06-13T13:44:49.330 に答える
7

単純に埋め込みスクリプト言語 ( Luaは埋め込みに最適) を使用したり、実行時に使用する C++ 用の独自のコンパイラを作成したりすることに加えて、本当に C++ を使用したい場合は、既存のコンパイラを使用することができます。

たとえば、Clangは、別のプログラムに簡単に埋め込むことができるライブラリとして構築された C++ コンパイラです。さまざまな方法で C++ ソースを分析および操作する必要がある IDE などのプログラムから使用するように設計されていますが、バックエンドとしてLLVMコンパイラ インフラストラクチャを使用すると、実行時にコードを生成し、関数ポインタを渡すこともできます。を呼び出して、生成されたコードを実行します。

于 2012-06-13T13:51:06.950 に答える
7

libtccを見てください。シンプル、高速、信頼性が高く、ニーズに合っています。C関数を「その場で」コンパイルする必要があるときはいつでもそれを使用します。

アーカイブには、examples/libtcc_test.cというファイルがあります。これにより、有利なスタートを切ることができます。この小さなチュートリアルも役立つかもしれません: http://blog.mister-muffin.de/2011/10/22/discovering-tcc/

#include <stdlib.h>
#include <stdio.h>
#include "libtcc.h"

int add(int a, int b) { return a + b; }

char my_program[] =
"int fib(int n) {\n"
"    if (n <= 2) return 1;\n"
"    else return fib(n-1) + fib(n-2);\n"
"}\n"
"int foobar(int n) {\n"
"    printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
"    printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
"    return 1337;\n"
"}\n";

int main(int argc, char **argv)
{
    TCCState *s;
    int (*foobar_func)(int);
    void *mem;

    s = tcc_new();
    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
    tcc_compile_string(s, my_program);
    tcc_add_symbol(s, "add", add);

    mem = malloc(tcc_relocate(s, NULL));
    tcc_relocate(s, mem);

    foobar_func = tcc_get_symbol(s, "foobar");

    tcc_delete(s);

    printf("foobar returned: %d\n", foobar_func(32));

    free(mem);
    return 0;
}

ライブラリを使用して問題が発生した場合は、コメントで質問してください。

于 2013-08-22T22:28:18.793 に答える
4

基本的に、プログラム内に C++ コンパイラを記述し (簡単な作業ではありません)、コードを実行するために JIT コンパイラが行うのと同じことを行う必要があります。あなたは実際には、この段落で 90% を達成しました。

これは簡単な方法では起こり得ないことは承知していますが、確かに可能であるに違いありません。コンパイルされておらず、C または C++ で実装されているようなものを動的に作成するプログラミング言語がたくさんあります。

まさに、それらのプログラムにはインタープリターが付属しています。--pythonpython MyProgram.pyはコンパイルされた C コードであり、その場でプログラムを解釈して実行することができます。これらの行に沿って何かを行う必要がありますが、C++ コンパイラを使用する必要があります。

動的関数が必要な場合、別の言語を使用してください:)

于 2012-06-13T13:44:29.267 に答える
3

このための典型的なアプローチは、C++ (またはそれが書かれているもの) プロジェクトをスクリプト言語と組み合わせることです。
Luaは、十分に文書化されており、小さく、多くの言語のバインディングがあるため、最も人気のある言語の 1 つです。

しかし、その方向性を検討していない場合は、動的ライブラリを利用することを考えてみませんか?

于 2012-06-13T13:46:00.263 に答える
1

はい - C++ 用のコンパイラを C++ で、いくつかの追加機能を使用して作成できます - 独自の関数を作成し、自動的にコンパイルして実行します (またはしない)...

于 2012-06-13T13:41:11.020 に答える
1

.NETを調べてくださいExpressionTrees- これは基本的にあなたが達成したいことだと思います。部分式のツリーを作成し、それらを評価します。オブジェクト指向の方法では、 の各ノードは、そのサブノードへの再帰によって、それ自体を評価する方法を知っている場合があります。次に、ビジュアル言語がこのツリーを作成し、それを実行する単純なインタープリターを作成できます。

また、このようなビジュアル プログラミング言語をどのように記述できるかについて、Java の例としてPtolemy IIを確認してください。

于 2012-06-13T14:44:25.300 に答える
0

パフォーマンスを求めていない場合の最も簡単な解決策は、LuaPythonなどのスクリプト言語インタープリターを埋め込むことです。

于 2012-06-13T13:42:32.853 に答える
0

このように私にとってはうまくいきました。-fpermissive フラグを使用する必要があります。CodeBlocks 17.12 を使用しています。

#include <cstddef>

using namespace std;
int main()
{
    char func[] = {'\x90', '\x0f', '\x1'};
    void (*func2)() = reinterpret_cast<void*>(&func);
    func2();
    return 0;
}
于 2018-11-02T08:47:15.940 に答える