3

私は一種のランタイムシステム/インタプリタを作成している最中です。実行できる必要があることの1つは、外部ライブラリにあるc /c++関数を呼び出すことです。

Linuxでは、dlfcn.h関数を使用してライブラリを開き、その中にある関数を呼び出しています。問題は、dlsysm()返された関数ポインタを使用する場合、呼び出される前に適切な型にキャストして、関数の引数と戻り型がわかるようにする必要があることです。ただし、ライブラリ内の任意の関数を呼び出す場合は、明らかにしません。コンパイル時にこのプロトタイプを知っています。

だから私が求めているのは、動的にロードされた関数を呼び出して引数を渡し、プロトタイプであることがわからなくても戻り値を取得する方法はありますか?

これまでのところ、これを行う簡単な方法はないという結論に達しましたが、私が見つけたいくつかの回避策は次のとおりです。

  • ロードしたいすべての関数が同じプロトタイプを持っていることを確認し、これらの関数がパラメーターと戻り値を取得するためのソートメカニズムを提供します。これは私が現在行っていることです。

  • インラインasmを使用して、パラメーターをスタックにプッシュし、戻り値を読み取ります。可能であれば、これを避けたいと思います。

誰かが何かアイデアを持っているなら、それは大いにありがたいです。

編集:

私は今、私が探していたものを正確に見つけました:

http://sourceware.org/libffi/

「ポータブルForeignFunctionインターフェイスライブラリ」

(私は元の質問でより明確であったかもしれないことを認めますが!)

4

5 に答える 5

6

あなたが求めているのは、C / C ++が関数のリフレクションをサポートしているかどうかです(つまり、実行時に関数の型に関する情報を取得します)。悲しいことに、答えはノーです。

関数を標準契約に準拠させるか(あなたが言ったように)、引数を知らずに実行時に関数を呼び出そうとするためのメカニズムの実装を開始する必要があります。

関数の知識がないと呼び出すことができないので、インタプリタ/「ランタイムシステム」には少なくともユーザー入力などがあり、それらを使って何かのように見える関数を呼び出そうとしていると推測できます。引数と完全に予期しないものを返す。そのルックアップは、リフレクションと適切なランタイム型システムを使用しても、それ自体で実装するのは困難です。呼び出し規約、リンケージスタイル、プラットフォームを組み合わせると、すぐに厄介になります。

計画に固執し、動的にロードする関数に対して明確に定義されたコントラクトを適用し、うまくいけばそれを実現します。

于 2010-07-07T12:15:38.987 に答える
2

外部ライブラリにディスパッチ関数を追加できますか?たとえば、ある種のバリアント型の関数名とN(オプション)パラメーターを受け取り、バリアントを返す関数を追加できますか?このようにして、ディスパッチ関数のプロトタイプがわかります。次に、ディスパッチ関数は関数名のルックアップ(またはスイッチ)を実行し、対応する関数を呼び出します。

当然、機能が多いとメンテナンスの問題になります。

于 2010-07-07T12:14:15.197 に答える
1

ruby FFI ライブラリは、あなたが求めていることを実現すると思います。外部の動的にリンクされたライブラリの関数を、特にリンクしなくても呼び出すことができます。

http://wiki.github.com/ffi/ffi/

おそらくスクリプト言語で直接使用することはできませんが、アイデアは移植可能です。

-- ブラッド・フェラン http://xtargets.heroku.com

于 2010-07-07T13:27:25.680 に答える
0

私は一種のランタイム システム/インタープリターを作成中です。実行できるようにする必要があることの 1 つは、外部ライブラリにある c/c++ 関数を呼び出すことです。

おそらく、TclPythonがそれを行う方法の例を確認できます。Perl に精通している場合は、Perl XSも確認できます。

一般的なアプローチは、インタプリタとターゲット C ライブラリの間に追加のゲートウェイ ライブラリを配置することです。Perl XS での私の経験から、主な理由は、メモリ管理/ガベージ コレクションと、インタプリタの言語に直接マッピングするのが難しい/不可能な C データ型です。

だから私が求めているのは、動的にロードされた関数を呼び出して引数を渡し、プロトタイプであることを知らずに戻り値を取得する方法はありますか?

私には知られていません。

ロードするすべての関数が同じプロトタイプを持っていることを確認し、これらの関数がパラメーターを取得して値を返すための並べ替えメカニズムを提供します。これが私が現在行っていることです。

これは、私のプロジェクトで他のチームも行っていることです。彼らは、次のような外部プラグイン用の標準化された API を持っています。

typedef std::list< std::string > string_list_t;
string_list_t func1(string_list_t stdin, string_list_t &stderr);

プラグインの一般的なタスクは、多くの場合 RDBMS を使用して、入力の変換、マッピング、または拡張を実行することです。

以前のバージョンのインターフェースは、時間の経過とともにメンテナンスが困難になり、顧客、製品開発者、およびサードパーティのプラグイン開発者の両方に問題を引き起こしました。std::string の軽薄な使用は、プラグインが比較的めったに呼び出されないという事実によって許可されます (それでもオーバーヘッドは、あらゆる場所で使用される SQL と比較してピーナッツです)。引数stdinには、プラグインのタイプに応じて入力が取り込まれます。出力パラメーター内の文字列が「E:」で始まる場合、プラグイン呼び出しは失敗したと見なされますstderr(「W:」は警告用で、残りは警告なしで無視されるため、プラグインの開発/デバッグに使用できます)。

dlsym、関数テーブル (関数のパブリック名、型、ポインターなど) を使用して共有ライブラリ配列から取得するために、定義済みの名前を持つ関数で 1 回だけ使用されます。

于 2010-07-07T13:40:49.060 に答える
0

generic proxy function私の解決策は、動的関数を次のような統一プロトタイプに変換する a を定義できることです。

#include <string>
#include <functional>

using result = std::function<std::string(std::string)>;

template <class F>
result proxy(F func) {
  // some type-traits technologies based on func type
}

ユーザー定義ファイルでは、変換を行うために定義を追加する必要があります。

double foo(double a) { /*...*/ }
auto local_foo = proxy(foo);

ランタイム システム/インタープリターでは、 を使用dlsymしてfoo-function. foo計算を行うのはユーザー定義関数の役割です。

于 2014-01-27T09:26:51.797 に答える