• ベストアンサー

C言語で型汎用性のある関数を作成したい

C言語です。 下記のコードでは、期待した通りにメンバにアクセスできるのですが、 構造体のメンバが多くなったとき、構造体をネストしているときには、 挙動がおかしく(なにか別の値をとりだしてしまっている?)なります。 どのようにしたら型汎用のある関数を書くことができるでしょうか? (C++ならば、汎用(テンプレート)関数があるけれども。。。) #include <stdio.h> struct hanyo{ int i; }; struct aaa{ int i; long l; char str[100]; }; struct bbb{ int i; }; void hoge(hanyo *ph){ printf("%d\n", ph->i); return; } int main(){ aaa a; a.i = 1; bbb b; b.i = 2; hoge((hanyo *)&a); hoge((hanyo *)&b); return 0; } ----実行結果---- 1 2 続行するには何かキーを押してください . . .

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.5

普通に考えると、マクロを使うしかないと思います。 #define hoge(ph) ((void)printf("%d\n", (ph)->i)) もっと複雑な関数の場合、関数定義用のマクロを作って、必要に応じて関数の定義を行うしかないでしょう。 #define DEFINE_hoge(type) \  void hoge_##type(type *ph) { \   printf("%d\n", ph->i); \  } DEFINE_hoge(aaa); DEFINE_hoge(bbb);

otaks
質問者

お礼

ご回答ありがとうございます。 構造体の種類の数だけ関数を作成するかと 自分も考えましたが、コードが冗長になってしまうと 思って躊躇しました。 しかし、マクロを使用すれば簡単に関数を 作成できるのですね 新たな発見です!

その他の回答 (5)

  • 0x131cc6e
  • ベストアンサー率36% (42/115)
回答No.6

私なら#1の方と同じくunionを使いますね。 種別を保持するメンバ変数の内容によって処理を振り分ける。

参考URL:
http://www.geocities.jp/ky_webid/c/047.html
otaks
質問者

お礼

長くなってしまってすいません。 補足に書いたのはサンプルプログラムとして 適当ではありませんでした。 以下に書き直します。 #include <stdio.h> #include <string.h> struct aaa{ int i; long l; char str[100]; }; struct bbb{ int i; }; struct hanyo{ int type; union { struct aaa a; struct bbb b; }data; }; void bar(struct hanyo *ph){ int i; switch(ph->type){ case 1: i = ph->data.a.i; break; case 2: i = ph->data.b.i; break; default: return; break; } /********************************/ /* iを使った共通の処理をここで */ /********************************/ printf("i = %d\n", i); return; } int main(){ hanyo h1, h2; memset(&h1, 0x00, sizeof(hanyo)); h1.type = 1; h1.data.a.i = 1; h1.data.a.l = 2; strcpy(h1.data.a.str, "test"); bar(&h1); memset(&h2, 0x00, sizeof(hanyo)); h2.type = 2; h2.data.b.i = 100; bar(&h2); return 0; }

otaks
質問者

補足

ご回答ありがとうございます。 サンプルコードを書いてみたのですが、 以下のような感じを想定されていますでしょうか? #include <stdio.h> #include <string.h> struct aaa{ int i; long l; char str[100]; }; struct bbb{ int i; }; struct hanyo{ int type; union { struct aaa a; struct bbb b; }data; }; void bar(struct hanyo *ph){ switch(ph->type){ case 1: printf("i = %d\n", ph->data.a.i); printf("l = %ld\n", ph->data.a.l); printf("str = %s\n", ph->data.a.str); break; case 2: printf("i = %d\n", ph->data.b.i); break; default: break; } return; } int main(){ hanyo h1, h2; memset(&h1, 0x00, sizeof(hanyo)); h1.type = 1; h1.data.a.i = 1; h1.data.a.l = 2; strcpy(h1.data.a.str, "test"); bar(&h1); memset(&h2, 0x00, sizeof(hanyo)); h2.type = 2; h2.data.b.i = 100; bar(&h2); return 0; } ---------実行結果----------- i = 1 l = 2 str = test i = 100 続行するには何かキーを押してください . . .

回答No.4

 どのような処理をどれだけ汎用化したいのかわからないけど、 #include <stdio.h> struct aaa{ int i; long l; char str[100]; }; void swap(void *a, void *b, size_t size) { char *p = a, *q = b; size_t i; for(i = 0; i < size; i ++){ char tmp = p[i]; p[i] = q[i]; q[i] = tmp; } } int main(void) { int a = 2, b = 3; double c = 2.0, d = 3.0; float e = 2.0, f = 3.0; char g = 'a', h = 'b'; struct aaa i = {1, 2, "hoge"}, j = {3, 4, "funya"}; printf("a = %d, b = %d\n", a, b); swap(&a, &b, sizeof(int)); printf("a = %d, b = %d\n", a, b); printf("c = %f, d = %f\n", c, d); swap(&c, &d, sizeof(double)); printf("c = %f, d = %f\n", c, d); printf("e = %f, f = %f\n", e, f); swap(&e, &f, sizeof(float)); printf("e = %f, f = %f\n", e, f); printf("g = %c, h = %c\n", g, h); swap(&g, &h, sizeof(char)); printf("g = %c, h = %c\n", g, h); printf("i = {%d, %ld, %s}, j = {%d, %ld, %s}\n", i.i, i.l, i.str, j.i, j.l, j.str); swap(&i, &j, sizeof(struct aaa)); printf("i = {%d, %ld, %s}, j = {%d, %ld, %s}\n", i.i, i.l, i.str, j.i, j.l, j.str); return 0; }

otaks
質問者

お礼

ご回答ありがとうございます。

  • Interest
  • ベストアンサー率31% (207/659)
回答No.3

具体的に何をしたいのでしょうか? オブジェクト指向ライクなことを考えているのでしたら、関数へのポインタを使って実際の処理を担当する関数の方を分けてしまうのが常道だと思います。 異なる構造体で同じメンバを含むことがあり、同じメンバに対して同じ処理をしたいのであれば、 typedef struct{  int a;  char b; }CommonPart; /* 共通部分 */ typedef struct{  CommonPart c;  int aa; }Aaa; typedef struct{  CommonPart c;  char bb[100]; }Bbb; void FuncForCommonPart(CommonPart *c) {  なにかてきとうに; } void FuncForAaa(Aaa *aaa) {  FuncForCommonPart(aaa->c); /* 共通部分の処理 */  Aaa固有の処理; } void FuncForBbb(Bbb *bbb) {  FuncForCommonPart(bbb->c); /* 共通部分の処理 */  Bbb固有の処理; } こうした方が、安全なんじゃないかと思います。

otaks
質問者

補足

ご回答ありがとうございます。 >具体的に何をしたいのでしょうか? >オブジェクト指向ライクなことを考えているのでしたら、 >関数へのポインタを使って実際の処理を担当する関数の方を >分けてしまうのが常道だと思います。 Cを使用してオブジェクト指向ライクなことをしたいと思って コードを書いているわけではありません。多分・・ Cでも関数ポインタを駆使して不完全なオブジェクト指向 プログラミングができることを知っているぐらいで、実際に どうやってコードを書けばよいのかは知らないです。また、 オブジェクト指向自体についても理解が浅いので、自分が オブジェクト指向ライクなことをしているのかどうかが 判別できません。 >異なる構造体で同じメンバを含むことがあり、 >同じメンバに対して同じ処理をしたいのであれば、 私がやりたいのはこちらですが、具体的には、関数に対して、 共通部分のデータを渡すのではなく、データ全体(この場合では 構造体変数ポインタ)を渡してやって後は関数の中で、 渡された構造体の中のデータを使いたいというものです。 ※渡す構造体の種類が複数あります。 ご回答にあるコードのように、渡す先の関数内で使用したいデータのみを 複数個、引数として関数に渡すことで現状は実装しているのですが、 関数に渡す際に構造体変数のポインタ型で渡したかったのです。

noname#208124
noname#208124
回答No.2

使う構造体全ての最初のメンバに識別するためのデータを突っ込んで処理をわける C++やJavaのクラスと違って->iとか->lなんてのはコンパイル段階で0バイト目、4バイト目でしかなくなる 無理なキャストでおかしくなるのは当然

  • don_go
  • ベストアンサー率31% (336/1059)
回答No.1

やろうとしている事が今一つ見えませんが.... 「共用体」ではどうでしょうか?

otaks
質問者

お礼

ご回答ありがとうございます。 共用体について調べてみます。

関連するQ&A

専門家に質問してみよう