No.15292![]() |
ポインタの型を場合分けで変える 投稿者---ねこのひげ(2004/07/06 19:35:32) |
||
こんにちは。 いつもお世話になっております。 下記の様に、ポインタの型を、kindの値によって変えたいのですが、 これですと、メンバを参照する部分で「定義されていないエラーです。」 とエラーが出てしまいます。 最初に適当に A *p_in = NULL; A *p_out = NULL; で宣言するとAccessViolationで落ちてしまいます。 このようなことはできないのでしょうか? ●A, B, Cは構造体で、それぞれのメンバ名は同じにしてあります。 ●環境は、VisualStudio6.0です。 int function(char *inbuf, char *outbuf, int kind) { switch (kind){ case 1: A *p_in = (A *)inbuf; A *p_out = (A *)outbuf; break; case 2: B *p_in = (B *)inbuf; B *p_out = (B *)outbuf; break; case 3: C *p_in = (C *)inbuf; C *p_out = (C *)outbuf; break; } /* 処理いろいろ */ function2(p_in->member1, p_out->member1); function3(p_in->member2, p_out->member2); ・・・ } |
No.15293![]() |
Re:ポインタの型を場合分けで変える 投稿者---REE(2004/07/06 19:51:36) |
||
>下記の様に、ポインタの型を、kindの値によって変えたいのですが、 >このようなことはできないのでしょうか? できません。 {}の中で宣言した変数は{}の中でだけ有効です。 結論から言うと、たとえ、メンバの名前が同じでも、それぞれ別の型の構造体であれば、同じように操作することは出来ません。 ねこのひげさんの考えている方法では、メンバにアクセスする度に、種類別にポインタをキャストする必要があります。 「バイナリデータを数値に変換」で私が言った「かなりややこしいことになりそうです・・」はこういうことです。 |
No.15295![]() |
Re:ポインタの型を場合分けで変える 投稿者---ねこのひげ(2004/07/06 20:05:47) |
||
REE様、いつもありがとうございます。 >できません。 そうでしたか・・・。ありがとうございます。 素直に使用する構造体によって、関数を分けます・・・。 >「バイナリデータを数値に変換」で私が言った「かなりややこしいことになりそうです・・」はこういうことです。 こういった事も含まれていたのですね。納得です。 精進致します。ありがとうございました。 |
No.15296![]() |
Re:ポインタの型を場合分けで変える 投稿者---shu(2004/07/06 20:12:30) |
||
共用体 http://www9.plala.or.jp/sgwr-t/c/sec16.html#s16-2 は使えませんか? |
No.15333![]() |
Re:ポインタの型を場合分けで変える 投稿者---YuO(2004/07/07 21:54:23) |
||
> ●A, B, Cは構造体で、それぞれのメンバ名は同じにしてあります。 同じメンバ名で型も同じですか? それであれば,共通部分を構造体にして,A, B, Cではなくその共通部分を渡すようにすればよいです。 #この延長線上に,VC++におけるクラスの実装が存在します。 そうでないなら, をマクロで展開させるしかなくなります。function2(p_in->member1, p_out->member1); function3(p_in->member2, p_out->member2); |
No.15430![]() |
Re:ポインタの型を場合分けで変える 投稿者---ねこのひげ(2004/07/11 23:56:56) |
||
shu様、YuO様、ありがとうございます。 また、返信が遅くなりまして申し訳ございません。 共用体は、今までどういう時に使うのか分からなかったのですが、 このような時に使うのですね! 早速、共用体を使って書いてみたのですが、、、 また分からなくなってしまいました。すみません。 下記のようにすると、 function2やfunction3を呼び出す時の引数をどう書けばよいのでしょう? それとも、そもそも、共用体の使い方を勘違いしていますか? --------------- typedef struct { char member1[1]; char member2[2]; char member3[3]; } A; typedef struct { char member1[5]; char member2[6]; char member3[7]; } B; typedef struct { char member1[1]; char member2[3]; char member3[5]; } C; function(char *, char *, int); void main() { char char_in[] = "abcdefghijklmnopqr"; char char_out[20]; function(char_in, char_out, 1); } int function(char *inbuf, char *outbuf, int kind) { union IN{ A *p_in_a; B *p_in_b; C *p_in_c; }; union OUT{ A *p_out_a; B *p_out_b; C *p_out_c; }; union IN in; union OUT out; switch (kind){ case 1: in.p_in_a = (A *)inbuf; out.p_out_a = (A *)inbuf; break; case 2: in.p_in_b = (B *)inbuf; out.p_out_b = (B *)outbuf; break; case 3: in.p_in_c = (C *)inbuf; out.p_out_c = (C *)outbuf; break; } /* 処理いろいろ */ function2(???->member1, ???->member1); function3(???->member2, ???->member2); ・・・ ----------- >同じメンバ名で型も同じですか? >それであれば,共通部分を構造体にして,A, B, Cではなくその共通部分を渡すようにすればよいです。 上記のように、型は同じですが、サイズが違います。 ということは、共通部分もないので、この方法は使えないですよね。 >マクロで展開させるしかなくなります。 共用体を使用して、かつ、 function2、function3の引数をマクロで宣言した値にする、 ということでしょうか? ------------ #define ARG_IN(x) p_in_x #define ARG_OUT(x) p_out_x として、case文の中で、 function2(ARG_IN(a)->member1, ARG_OUT(a)->member1); ------------ これだと、意味ないですよね・・・。 すみません、どのようなマクロを宣言&使用すれば良いのか、 教えていただけますでしょうか。 |
No.15435![]() |
Re:ポインタの型を場合分けで変える 投稿者---YuO(2004/07/12 00:55:11) |
||
> 上記のように、型は同じですが、サイズが違います。 型が同じなのにサイズが異なるということはあり得ません。 char [1]型とchar [5]型は別の型です。 #A::member1はchar [1]型であってchar型ではない。 >> マクロで展開させるしかなくなります。 > 共用体を使用して、かつ、 > function2、function3の引数をマクロで宣言した値にする、 > ということでしょうか? #undef FUNCTION_IMPLEMENT #define FUNCTION_IMPLEMENT(type) \ int function_##type (type * inbuf, type * outbuf) \ { \ function2(inbuf->member1, outbuf->member1); \ function3(inbuf->member2, outbuf->member2); \ /* ... */ \ } #undef FUNCTION_INVOKE #define FUNCTION_INVOKE(type, inbuf, outbuf) \ function_##type(inbuf, outbuf) FUNCTION_IMPLEMENT(A) FUNCTION_IMPLEMENT(B) FUNCTION_IMPLEMENT(C) というようにして,FUNCTION_INVOKEを使って呼び出すようにします。 呼び出しコードを変えたくないのであれば, int function (void * inbuf, void * outbuf, int kind) { #undef FUNCTION_IMPLEMENT #define FUNCTION_INPLEMENT(type) \ do { \ function2((type *)inbuf->member1, (type *)outbuf->member1); \ function3((type *)inbuf->member2, (type *)outbuf->member2); \ /* ... */ \ } while (0) switch (kind) { case 1: FUNCTION_IMPLEMENT(A); break; case 2: FUNCTION_IMPLEMENT(B); break; case 3: FUNCTION_IMPLEMENT(C); break; } return /* ... */ ; #undef FUNCTION_IMPLEMENT }のようになります。 そもそも,型が異なるものを同じコードで動かそう,というところに無理があるのです。 Cでは,名前が同じであっても大して意味をもちません。 今回の場合,素直にC++のtemplateを使うべきだと思います。 最初のマクロは,templateと同じことを強引にCで書いた物です。 ちなみに,C++で書くと, template <typename T> int function (T * inbuf, T * outbuf) { function2(inbuf, outbuf); function3(inbuf, outbuf); /* ... */ }と,非常に読み易く,素直になります。 |
No.15478![]() |
Re:ポインタの型を場合分けで変える 投稿者---ねこのひげ(2004/07/13 12:11:04) |
||
YuO様、shu様、ありがとうございます。 >型が同じなのにサイズが異なるということはあり得ません。 >char [1]型とchar [5]型は別の型です。 そうだったのですか!char[x]型はchar型だと思っておりました。 表現が不適切だったために、余計なお手間を取らせてしまいまして、 申し訳ございませんでした。 >#undef FUNCTION_IMPLEMENT >・・・ >#undef FUNCTION_IMPLEMENT >} おお!すごいです!このようなマクロを使うのですね。 まだ、マクロと言うと定義部分の短い、簡単なものしか 思いつくことができず、このように長いものは初めてです。 自分でも、これが思いつくようになるよう、もっと勉強いたします。 >そもそも,型が異なるものを同じコードで動かそう,というところに無理があるのです。 やはり、そうなのですね。すいません。 >今回の場合,素直にC++のtemplateを使うべきだと思います。 VisualStudioを使っているくせに、C++はさっぱり・・・ なのですが、C++も習得したい言語なので、こちらも貴重な情報として、 参考にさせていただきます。 大変有益なレスを、ありがとうございました。 >function(char_in, char_out, 1); >の処理で、char_outにはどういう文字列が入りますか? char_inは、上記で書いた例では"abcdef・・・"ですが、 実際には、複数の文字コードやバイナリのデータが混ざった文字列です。 それを、function2やfunction3で文字コードの変換をし、 変換結果が、char_outに入るようになっています。 例えば、構造体A, B, Cの member1は、EBCDIK→JISに変換、 member2は、バイナリデータなので変換なし、 member3は、JIS→SJISに変換 というような感じです。 |
No.15445![]() |
Re:ポインタの型を場合分けで変える 投稿者---shu(2004/07/12 09:47:31) |
||
> typedef struct { char member1[1]; char member2[2]; char member3[3]; } A; typedef struct { char member1[5]; char member2[6]; char member3[7]; } B; typedef struct { char member1[1]; char member2[3]; char member3[5]; } C; function(char *, char *, int); void main() { char char_in[] = "abcdefghijklmnopqr"; char char_out[20]; function(char_in, char_out, 1); } function(char_in, char_out, 1); の処理で、char_outにはどういう文字列が入りますか? 最終的にどういう感じの出力にしたいのでしょうか? 文字列から3文字ずつ取ってきてそれをひとつの文字列にするのかな? |
No.15482![]() |
Re:ポインタの型を場合分けで変える 投稿者---ねこのひげ(2004/07/13 12:56:28) |
||
No.15478を投稿する場所を間違えてしまいました。 本来は、ここにくるべきものです。 |
No.15476![]() |
Re:ポインタの型を場合分けで変える 投稿者---REE(2004/07/13 11:25:35) |
||
>function2やfunction3を呼び出す時の引数をどう書けばよいのでしょう? >それとも、そもそも、共用体の使い方を勘違いしていますか? 共用体の使い方はあっていると思いますが、今回の場合には、全く役に立ちません。 共用体は、同じメモリ範囲を違う名前や大きさで扱うためのものです。 A,B,Cなどをやめて、下記の様にすることをお勧めします。 typedef struct { int start; int size; // きっと必要になる } area; struct { area member1; // 配列でも可 area member2; area member3; } format[] = {{{0, 1}, {1, 2}, { 3, 3}}, {{0, 5}, {5, 6}, {11, 7}}, {{0, 1}, {1, 3}, { 4, 5}}}; int function(char *inbuf, char *outbuf, int kind) { function2(inbuf + format[kind].member1.start, outbuf + format[kind].member1.start); ... } こうした場合、function2の引数にメンバのサイズを追加する必要が出てくると思われます。 |
No.15481![]() |
Re:ポインタの型を場合分けで変える 投稿者---ねこのひげ(2004/07/13 12:54:19) |
||
REE様、ありがとうございます。 > A,B,Cなどをやめて、下記の様にすることをお勧めします。 > typedef struct > ・・・ > こうした場合、function2の引数にメンバのサイズを追加する必要が出てくると思われます。 おお!、これは、とてもすっきりしていて良いですね。 パディングの問題も出ないですし、まとめたかった関数もまとまっていますし。 まだ、文法は理解していても、それを使いこなすことができていなくて、 恥ずかしい限りですが、このようなものをすぐに思いつくようになるように 頑張りたいと思います。 いずれ、また何かお聞きすることが出てくるかもしれませんが、 どうぞよろしくお願い致します。 |