質問
私は、他のプロセスは、(Unixソケットを介して)上の関数を呼び出すことができるようにしたい、このプログラムを持っています。メッセージプロトコルは、関数名、関数シグネチャ、およびパラメータを保持するバッファ(チャー*)非常に簡単である。
私のプログラム内のモジュールは、関数がアクセスできるように許可したい場合は、、それはライブラリと名前と署名を登録します。私が直面してる問題は、私はRPCやJava RMIのようなライブラリを見てきました。要求が入ってきたら、物理的に関数を呼び出すことであるが、これらは私が呼び出しをラップするスタブを生成する必要があります。私が働いているシステムは非常に動的であり、また、私は変更することはできません他の人のコードとインタフェースする必要があります。
だから、基本的に、この関数は次のようになります。
int somefunc(int someparam, double another)
{
return 1234;
}
今、私は、ライブラリに登録します:
// func ptr name signature
REG_FUNCTION(somefunc, "somefunc", "i:id");
リクエストが来たとき、私はいくつかのエラーチェックを行い、いったん有効な私は、関数を呼び出したいです。だから私は、変数を持っています:
void * funcptr = (the requested function);
char * sig = (the function signature);
char * params = (a buffer of function parameters);
//note that the params buffer can hold data types of arbitrary lengths
どのように私はCでパラメータで関数を呼び出すことができますか?
ありがとうございます。
解決
私は、これは、例えば、あなたがターゲット関数で使用される呼び出し規約を知らないだけでC.を使用して、一般的には完全に解けるではないと思います。あなたは、コンパイラを「不正行為」、あるいは少なくともそれを第二推測するに終わる危険性があります。コンパイラは、おそらくいくつかの最適化設定に、レジスタに渡された引数を使用して登録した機能を構築することを決めた場合はどうすれば(それは別のコンパイラでビルドされた場合、または何?)ます。
あなたは、引数の与えられたセットで関数を呼び出すしたいというC言語で表現し、引数の値がランダムバイトのバッファからアンパックする必要があると一般的に手立てもありません。
あなたはこのような恐ろしい何かができます
enum { VOID_INT, VOID_INT_DOUBLE, VOID_DOUBLE_INT, ... } Signature;
void do_call(const void *userfunction, const void *args, Signature sig)
{
switch(signature)
{
case VOID_INT:
{
int x = *(int *) args;
void (*f)(int) = userfunction;
f(x);
break;
}
case VOID_INT_DOUBLE:
...
}
}
しかし、これは、スケーラビリティと同じ大陸に住んでいないことは明らかです。もちろん戻り値の型と引数の型のいくつかの合理的なセットのために、このコードを自動生成することができます。あなたはまだvoid *
へ/から関数ポインタをキャストする寒さの中に少しアウトだろうが、それは許容できるかもしれません。あなたはまだ、常にしかし、あなたがのために事前に生成されたコードを持っていない署名を手渡し誰かのリスクを実行したい。
他のヒント
libffi にチェックしてください。このライブラリは、実行時に指定されたパラメータのセットを使用して機能を呼び出すことができます。