2016-06-14 3 views
0

私はパラメータとして異なる構造体の型を受け取ることを可能にするC言語の関数を探しています。私は3つの異なる構造異なる構造で動作できる(C言語で)関数を作成することは可能ですか?

struct a{ 
    struct datatype0{ 
     char test1[10]; 
    }datatype; 
    struct a *next; 
}; 

struct b{ 
    struct datatype1{ 
     int test1; 
     char test2[20]; 
     int test3; 
    }datatype; 
    struct b *next; 
}; 

struct c{ 
    struct datatype2{ 
     char test1; 
     char test2; 
     float test3; 
     int test4; 
     int test5; 
    }datatype; 
    struct c *next; 
}; 

を作成した場合 例えば、私ができ、パラメータとしてtheese三つの異なる構造体のいずれかを受信するので、私は最初の初期化のためにのみそれを呼び出す、または第二または第三の種類ができる関数を作成したいです構造:

void function("---")//<-- inside the brackets i need to insert a parameter that can be struct a, or struct b or struct c. 
{ 
//here for example I can insert the initialize function that have to work with any struct. 

} 

私は労働組合を使用するようにしようと試みたが、私は、私は構造体の種類ごとに初期化する機能を再作成する必要があることを見て...私は、ボイドポインタを使用するためにしようと試みたが、私は内側にtheeseキャストする必要があります私は構造体の各種類の関数を初期化する必要があります... 任意のアイデア??

+4

どのC? C11では、ジェネリックがこれを行えるようにします。 C89またはC99では、ディスパッチ機械を自分で構築する必要があります。 –

+4

これを行うのは稀です。 – nucleon

+3

ええ、おそらく_Genericは使用しないでください。あなたは組合と一緒に正しい道を歩いています。 「各種類の構造体の初期化関数を再作成する必要があります」という意味を説明できますか? – BadZen

答えて

0

一部は機能します。私はのような関数を作成したい場合でも、例えば、:

typedef union elemento{ 
    struct a A; 
    struct b B; 
    struct c C; 
}elemento; 

void inserimentoOrdinato(elemento dausare){ 
    struct b prova; 
    prova.datatype.test1 = 3; 
    strcpy(prova.datatype.test2,"TESTA"); 
    prova.datatype.test3 = 200; 
    prova.next = (struct a*)malloc(sizeof(struct a)); 
    dausare.B = prova; 
} 

私は構造の異なる種類の「dausare.B」または「dausare.C」を使用する必要があります。組合のどの部分を使わなければならないのかは分かりません。私はリグですか?ありがとうございました!

+1

注:型(変数のポインタと一致しない可能性がある)、 'prova.next = malloc(sizeof * prova.next);で割り振るのではなく、変数の参照型で割り振ることを検討してください。 – chux

+0

BTW:このコードは、呼び出しコードの 'elemento'を初期化できません。 'dausare'は、呼び出し元コードの' elemento'のコピーです。したがって、 'dausare'への変更は、関数の完了後には見られません。私は 'void inserimentoOrdinato(elemento * dausare、int type){' – chux

+0

のようなものを期待しています。機能の中から変更がないことは分かっています!:)そして私は解決策を見つけたと思います。それがうまくいくなら、私はここにそれを掲示するでしょう。 –

1

長いと短いです:可能な限りこれを避けてくださいが、あなたが本当にする必要がある場合は異なる構造体を渡すことができます。

おそらく最も簡単な方法は、2つのメンバーを含むラッパー構造体を作成することです:共用体と、どの構造体が渡されるかを知らせるフラグ。

typedef enum { 
    A, 
    B, 
    C 
} struct_type; 

struct _wrapper { 
    union { 
     struct a A; 
     struct b B; 
     struct c C; 
    }; 
    struct_type flag; 
}; 

void my_function(struct _wrapper *data) 
{ 
    switch (data->flag) 
    { 
     case A: 
      struct a val = data.A; 
      //do stuff with A 
      break; 
     case B: 
      struct b val = data.B; 
      break; 
     case C: 
      struct c val = data.C; 
      //... 
      break; 
    } 
} 

もう一つの選択肢、それは悪い習慣と考えられていて、あなたは後悔してしまいます何かがあなたがキャストすることができます任意の構造体の最初のメンバのオフセットが0であることが保証されているという事実に依存することですが、最初のメンバーへのポインタに対する構造体へのポインタ。すべての構造体の最初のメンバーが互換性がある場合は、それに頼ることができます(の責任で)。そして

struct a { 
    void (*common_member)();// 
    /** other members **/ 
}; 
struct b { 
    void (*common_member)();//needn't be the same name though 
    /** other members **/ 
}; 

:これを利用するの
一つの方法は、第1部材としての関数ポインタか、構造体を識別するためのフラグとして使用できる列挙フィールドを設定することである

void my_func(void *data) 
{//void pointer 
    ((void (*)(void *))data)(data);//cast void *data to function pointer, and pass itself as an argument 
} 

この構造体が適切に初期化され、メンバーが正しい関数を指している場合は機能しますが、実際に依存するには多すぎます。

最初のメンバーとして列挙型を使用するのは、やや危険性は低いですが、それでも推奨できません。これは、関数ポインタとユニオンのアプローチの組み合わせの一種です。

void my_func(void *data) 
{ 
    //cast void * to struct_type *, dereference AFTER the cast 
    //because you can't dereference a void * 
    switch(*((struct_type *) data)) 
    { 
     case A: /* stuff */ break; 
     case B: /* struct b */ break; 
    } 
} 

まったく、最初のアプローチを使用します。関数ポインタのメンバを使用せず、3番目のアプローチを認識してください:実際には、ラッパー構造体は必要ありませんが、元のアプローチ(関数ポインタ)よりはるかに安全であり、あまり冗長ではありません最初のアプローチ(共用体で)。

ボトムライン:

**ボイド*は任意の構造体へのポインタ

宣言の一部とすることができます。構造体と共用体は、答えはジェネリックプログラミングと関数ポインタである

0

を移動するための方法です。

typedef void *Initializer(void* obj);//since every struct has its own fields to initialize 

void function(void * obj, Initializer init) 
{ 
    init(obj); 
} 

使用法:

void InitA(void* a_void) 
{ 
    struct a* a = (struct a*) a_void; 
    //init a feilds 
    a->next = NULL; 
} 

void InitB(void* b_void) 
{ 
    struct b* b = (struct b*) b_void; 
    //init b feilds 
    b->next = NULL; 
} 

void InitC(void* c_void) 
{ 
    struct c* c = (struct c*) c_void; 
    //init a feilds 
    c->next = NULL; 
} 

int main() 
{ 
    struct a a; 
    struct b b; 
    struct c c; 

    Init(&a,InitA); 
    Init(&b,InitB); 
    Init(&c, initC); 

    return 0; 
} 

***初期化するフィールドが同じ場合、構造体ごとに異なる関数を作成する必要はありません。

関連する問題