2

他のプロセスが(UNIXソケットを介して)関数を呼び出せるようにするこのプログラムがあります。メッセージ プロトコルは非常に単純で、関数名、関数シグネチャ、およびパラメーターを保持するバッファー (char *) です。

プログラム内のモジュールが関数にアクセスできるようにする場合、名前と署名をライブラリに登録します。私が直面している問題は、要求が入ったときに関数を物理的に呼び出すことです。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 でパラメーターを使用して関数を呼び出すにはどうすればよいですか?

ありがとう!

4

2 に答える 2

2

これは、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 *が、それは許容できるかもしれません。ただし、事前に生成されたコードを持っていない署名を誰かが手渡すリスクは常にあります。

于 2009-04-09T06:55:37.610 に答える
0

libffiをチェックしてください。このライブラリを使用すると、実行時に指定された一連のパラメーターを使用して関数を呼び出すことができます。

于 2011-11-23T13:26:18.603 に答える