2012-04-16 8 views
3

はのは、私は別の引数の数と、機能のかなり大量に持っているとしましょう。関数ポインタ、デザイン

POQ:私は彼らのパラメータ数を含め、正確な機能を知らなくても、それらを操作できるように

int print_one(int x) 
{ 
    printf("one: %d\n", x); 
    return 1; 
} 

int print_three(int x, int y, int z) 
{ 
    printf("three: %d-%d-%d\n", x, y, z); 
    return 3; 
} 

は今、私は、構造中にこれらの機能にいくつかのプロパティを接続したい(私も呼ぶかもしれません構造・インターフェース)

私はこの、(&私はかなり間違っていると思う)のようにそれをtryd:私はこのsolutiを見つける

typedef int (*pfunc)(int c, ...); 

typedef struct _stroffunc 
{ 
    pfunc myfunction; 
    int flags; 
    int some_thing_count; 
    int arguments[10]; 
    int argumentcount; 
} stroffunc; 

int main() 
{ 
    stroffunc firststruct; 

    firststruct.pfunc = (pfunc) print_two; 
    firststruct.something_count = 101; 
    arguments[0] = 102; 
    argumentcount = 1; 
    flag &= SOME_SEXY_FLAG; 

    // now I can call it, in a pretty ugly way ... however I want (with patially random results ofc) 
    firststruct.pfunc(firststruct.arguments[0]); 
    firststruct.pfunc(firststruct.arguments[0], 124, 11); 
    firststruct.pfunc(1, firststruct.arguments[0], 124, 1, 1); 
} 

非常に醜い、&私は(希望)より良い解決策は、&を呼び出して、関数のポインタを設定すると思います。

私はこのコードをコンパイルしませんでしたが、私は&をコンバートしてコンセプトが動作するようにしました。 注:純粋なCが必要です

+1

variadic関数ポインタにキャストし、それを介して関数を呼び出すと、未定義の動作が発生します。まず、variadic関数への引数は、*デフォルトの引数のプロモーション*を受けることを思い出してください。*これは本当にうまくいくでしょう。 –

答えて

1

可変長関数ポインタを使用して非可変関数を呼び出すと、の不確定な動作になります。最初に、可変引数関数の引数がデフォルト引数のプロモーションcharintなどに変換されます)を実行することを思い出してください。

異なる数の引数を持つ関数をどのように、あるいはなぜ動的に呼び出すのかははっきりしません。しかし、1つの解決方法は、ユニオンを使用することです。

typedef struct { 
    int num_args; 
    union { 
     void (*f1)(int); 
     void (*f2)(int, int); 
     void (*f3)(int, int, int); 
    } func; 
} magic; 


... 

magic m; 
... 
switch (m.num_args) { 
case 1: m.func.f1(arg1); break; 
case 2: m.func.f2(arg1, arg2); break; 
case 3: m.func.f3(arg1, arg2, arg3); break; 
default: assert(0); 
} 

2つ目の解決方法は、すべての関数を可変的に書き換えることです。

+0

私の関数を可変的に書き直すということは、私のすべての関数の最後に "、...)"を書くことを意味しますか? – lerosQ

+0

@lerosQ:そうです。しかし、これは、バラバラに渡すことを意図したパラメータ(つまり、あなたの例のすべてのパラメータ)を明示的に宣言することができなくなることを意味します(例えば 'int print_three(int x、...)')。 –

0

これは私の知るところではありますが、ABIの非互換性のために関数を可変的にする必要があると考えています。

は、以下を参照してください。wikipedia's example

+0

私はvariadicである型を定義しました、私はvariadicに関数をキャストしています。 – lerosQ

+0

しかし、関数自体は可変関数ではなく、ABI(スタック対レジスタrx0-9など)に応じて、同じ場所に格納されない通常の変数を使用します。 –

+0

私はそれが働いているかどうかを誤解していると思います。あなたがそれを知らないのであれば、私はその問題が何かを知らないのです...あなたは "匂い"が気に入らないのですか? –

0

はたぶん、あなたは「擬似」クラスのような構造体を、処理するためにいくつかの機能を持っているライブラリを追加することができ、この関数は、構造体へのポインタを保存します

int initFunc(int (*pfunc)(int c,...)); 

、 POOの文脈のように、構造体では、idを使ってそれぞれを呼び出すすべての関数の "マップ"のように使用します。

IDを返し、そしてあなたは、アレイに保存し、 その後、別のfuncは各ID

であるあなたがしなければならない今、その機能を確認してください、あなたは機能IDとパラメータを言う

int call(int id,int p1,...); 

を言います

+0

これは、可変的な関数ポインタを介して非可変的な関数を呼び出すことは、未定義の動作であり、何かを壊すことがほぼ確実であるという不運な問題を逃しています。 –