2012-04-23 10 views
3

私は関数名からなる文字列を受け取るディスパッチ関数の一種をCで書こうとしていますが、ディスパッチ関数の中からディスパッチ関数の名前を持つ関数を呼び出すことができます受け取った引数に指定されています。要点は、動的にロードされたライブラリに関数を定義したくないということです。流れはこのようなものでなければなりません。静的リンクライブラリのdlsymのような振る舞い

FILE1.C

void hello() 
{ 
    fprintf(stderr,"Hello world\n"); 
} 

void myfunc() 
{ 
    mydispatch("hello"); 
} 

file2.c私はこのような構造は、種の奇妙かもしれ知っているが、1は、この操作を行うことができれば、私は主に思っていた

void mydispatch(const char *function) 
{ 
... 
} 

答えて

2

実行時にシンボル名からアドレスを取得するためにBFDを使用できます。この場合

#include <stdio.h> 
#include <stdlib.h> 
#include <bfd.h> 
#include <string.h> 

void func1(int n) 
{ 
    printf("%d\n", n); 
} 

void * addr_from_name(char * filename, char * symname) 
{ 
    bfd *  ibfd; 
    asymbol ** symtab; 
    symbol_info info; 
    void *  symaddress = NULL; 
    long   size; 
    long   syms; 
    unsigned int i; 

    bfd_init(); 

    ibfd = bfd_openr(filename, NULL); 
    bfd_check_format(ibfd, bfd_object); 

    size = bfd_get_symtab_upper_bound(ibfd); 
    symtab = malloc(size); 
    syms = bfd_canonicalize_symtab(ibfd, symtab); 

    for(i = 0; i < syms; i++) { 
     if(strcmp(symtab[i]->name, symname) == 0) { 
      bfd_symbol_info(symtab[i], &info); 
      symaddress = (void *)info.value; 
     } 
    } 

    bfd_close(ibfd); 
    return symaddress; 
} 

int main(void) 
{ 
    void (*func)(int) = addr_from_name("/homes/mk08/Desktop/lala", "func1"); 
    printf("%p\n", func); 
    func(5); 
    return EXIT_SUCCESS; 
} 

、私はfilenameをハードコードが、動的にそれを得るために簡単です。コンパイルとそのように実行することができ、あなたのソース/バイナリがlalaと呼ばれていると仮定すると:私のシステムで

gcc -Wall -std=gnu99 lala.c -o lala -lbfd && ./lala 

を、これは印刷します

0x400814 
5 

注意このメソッドはそのままシンボルテーブルが必要であること。オーバーヘッドを減らすために、上記のコードを初期化ルーチンで再利用することができます。そこには、関数名からアドレスへのマッピングを格納します。これは、ルックアップテーブルを生成するための1回限りのコストをもたらす。

0

あなたは確かに、このようにそれを行うことができます。

void mydispatch(const char *function) 
{ 
    if (!strcmp(function, "hello") 
     hello(); 
    else if (!strcmp(function, "goodbye") 
     goodbye(); 
} 

、あなたは良い会社になるだろう。古くからこのように多くの通訳者が建てられました。

もっと動的なものを実行する限り、必要な実行時構造は静的リンクされたライブラリには存在しません。あなたが何をしていても、(ここに示したような)ディスパッチテーブルを手動または自動で作成する必要がありますが、自分でそれを行う必要があります。

FILE1.C:

void myfunc() 
{ 
    my_function_type fun = search_function("operation1"); 
    fun(); 
} 

のTools.h:

typedef void (*my_function_type)(void); 
void register_function(my_function_type fp, const char* name); 
my_function_type search_function(const char* name); 

file2.c:

static void mydispatch(void) 
{ 
... 
}  

static void __attribute__ ((constructor)) register_functions() 
{ 
    register_function(mydispatch, "operation1"); 
} 
+0

ええ、これは目的全体を敗北させ、さらに、ディスパッチできる20以上の方法を考えていると非常に面倒なコードになります。 – skyel

+0

私が言ったように、あなたがそれについて賢明なら、それを自動的に行うことができます。ディスパッチャはスクリプトによって生成することもできますし、少なくとも、単純なマクロの連続アプリケーションとして書くこともできます。 –

+0

実行時にこのようなことができるかどうかは実際にはわかりません。 2つのファイルのアイデア全体は、以前の時点でfile2.cをコンパイルし、後でそれを変更することなく使用することができました。たとえば、利用可能なメソッドの_char ** _をfile2.cに静的にすることができます。また、いくつかの関数によってidに追加することができます。次に、ディスパッチがあなたの呼び出しの正当性をチェックできます。スクリプト/マクロを使用する場合は、毎回再コンパイルする必要があります。 – skyel

0

はたぶん、あなたは、ソリューションの以下のようなものをseachingています

このソリューションでは、機能を追加すると、古いファイルを再度コンパイルすることができます。 新しいファイルとリンクをコンパイルするだけです。