1

以前に Java で解決した次のユースケースがありますが、プログラムを C に移植する必要があります。

抽象クラス Engine に属するメソッド do_work() を呼び出すメソッド A がありました。クラスの各具体的な実装は、次のように構築されました。

ユーザーは do_work() メソッドの定義を送信します。この定義が正しければ、プログラマーは Java Compiler API を使用して Engine クラスの具体的な実装を作成します。(このためのコードは、以下の参照用に含まれています)。

Cで同様のことを行うにはどうすればよいですか:

これで、do_work() メソッドへの関数ポインターを持つ構造エンジンができました。ユーザーが実行時にこのメソッドを送信できるようにしたい (注: これは起動時に一度だけ発生し、エンジン構造が構築されたら変更したくない) コマンドライン経由で。

どうすればこれについて行くことができますか?これを行うにはアセンブリを使用する必要があるという提案や、これは不可能であるという提案を読んだことがありますが、適切な説明や参照を提供するものはありませんでした。どんな助けでも大歓迎です。

このソリューションは 32/64 ビット マシンと互換性がある必要はありません。これが作成されたプログラムは 64 ビット マシン専用だからです。

参考までに、Java コード:

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    StandardJavaFileManager stdFileManager = compiler
            .getStandardFileManager(null, Locale.getDefault(), null);
    Iterable<? extends JavaFileObject> compilationUnits = null;

    String[] compileOptions = new String[] { "-d", "bin" };
    Iterable<String> compilationOptions = Arrays.asList(compileOptions);


        SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject(
                "package.adress",getCode());
        JavaFileObject javaFileObjects[] = new JavaFileObject[] { fileObject };
        compilationUnits = Arrays.asList(javaFileObjects);
    }

    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
    CompilationTask compilerTask = compiler.getTask(null, stdFileManager,
            diagnostics, compilationOptions, null, compilationUnits);

    boolean status = compilerTask.call();

    if (!status) {// If compilation error occurs
        /* Iterate through each compilation problem and print it */
        String result = ""; 
        for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
            result = String.format("Error on line %d in %s",
                    diagnostic.getLineNumber(), diagnostic);
        }
        Exception e = new Exception(result);
        throw e;
    }

    stdFileManager.close();// Close the file manager

    /*
     * Assuming that the Policy has been successfully compiled, create a new
     * instance
     */

    Class newEngine = Class
            .forName("package.name");

    Constructor[] constructor = newPolicy.getConstructors();
    constructor[0].setAccessible(true);
    etc.
}
4

1 に答える 1

2

Cでは、使用する前にすべてのコードをネイティブコードにコンパイルする必要があるため、コマンドラインコンパイラを使用してユーザーから送信されたコードをビルドするしかありません。たとえば、GNUC++コンパイラまたはVisualC++コンパイラの場合があります(ただし、Visual C ++の場合、法的な問題についてはわかりません。ライセンスによって許可されていますか)。したがって、まず、コンパイラ、おそらくGNUコンパイラを選択します。

次に、実行可能プログラムまたはDLLとしてコンパイルできます(ソフトウェアがWindows用であると想定しています)。DLLにコンパイルする場合は、Win32関数LoadLibraryを使用して、新しくビルドされたDLLをプロセスにロードする必要があります。その後、GetProcAddress関数を使用してメソッドアドレスを取得し、C ++から動的に呼び出すことができます(関数ラッパーを実装する必要があります)。 DLLで公開します)。

EXEファイルとしてコンパイルする場合は、CreateProcess関数を使用してコードを実行し、コマンドラインを介してパラメーターを送信してデータを受信する必要があります。パイプを使用する場合(CreatePipe関数を参照)、一時ファイルを使用する場合などがあります。 Windowsで利用可能な他のプロセス間通信方法。

DLLではユーザーコードにバグがあるとメインプログラムがクラッシュする可能性があるため、あなたの状況ではEXEファイルにコンパイルする方が良いと思います。

于 2013-01-22T12:39:48.283 に答える