質問 |
||
| 質問者:usatan2 | 構造体へのポインタ変数 | |
|---|---|---|
困り度:
|
9バイトのデータがあって、先頭の1バイトの値によって、残り8バイトが2バイトデータ4つの場合と、4バイトデータ2つの場合があります。 つまり、 struct typeA { char a; int s,t,u,v;}; struct typeB { char a; long x,y}; char *p; pがそのデータの先頭を指している場合、 typeAならば、p->s とアクセスし、 typeBならば、p->x とアクセスしたいのですが、エラーになってしまいます。 思いついた対処法は、 struct typeA pa; struct typeB pb; を定義しておいて、 pa = p; pa->s pb = p; pb->x としてアクセスする方法ですが、新たに変数に代入するのが無駄(実際はコンパイラの最適化で問題ないとは思いますが)なので、もっと直接的に p->s とアクセスする方法ありませんか? |
|
質問投稿日時:08/04/08 22:03 質問番号:3933334 |
||
回答 |
|
| 回答者:titokani | #9です。 Cでは無理だなんて書いてません。 構造体が使えないというだけです。 例えば、 inline int get_type(const char *p) { return p[0]; } inline int get_s(const char *p) { return p[1]|(p[2]<<8); } inline int get_t(const char *p) { return p[3]|(p[4]<<8); } inline int get_x(const char *p) { return p[1]|(p[2]<<8)|(p[3]<<16)|(p[4]<<24); } といった感じですね。 |
|---|---|
| 種類:回答 どんな人:専門家 自信:自信あり |
|
| |
回答日時:08/04/11 09:35 回答番号:No.10 |
|
| この回答へのお礼 | 再度、回答ありがとうございます。 >Cでは無理だなんて書いてません。 >構造体が使えないというだけです。 そうでしたね(笑)、失礼しました。 今回はCで書くより、インラインアセンブラのほうが素直かと思っただけです。 |
回答良回答20pt |
|
| 回答者:titokani | >9バイトデータはgivenです。通信回線からの受信データを想定しています。バッファから1パケット分のデータを受け取り、それを加工するプログラムです。char *p は、これから処理すべきデータの先頭(パケットの先頭ではありません)を指しています。 それでしたら、そもそも構造体は使えません。 アライメントの問題もそうですが、エンディアンの問題もあります。 char[9]で受け取って、1バイトづつ並び替える関数を作るのが現実的ですね。 |
|---|---|
| 種類:回答 どんな人:専門家 自信:自信あり |
|
| |
回答日時:08/04/09 16:24 回答番号:No.9 |
|
| この回答へのお礼 | 回答ありがとうございます。 今回、通信相手も同じCPUですので、エンディアンの問題はありませんが、アドバイス感謝します。 >それでしたら、そもそも構造体は使えません。 Cでの記述が無理なら、あからさまに、該当CPU限定の記述になりますが、インラインアセンブラで記述することにします(苦笑) |
回答 |
|
| 回答者:Tacosan | C99 いわく「正しくアラインされていないポインタを使ったらどうなってもしらないよ」だそうです. つまり, short が 2バイトだと仮定すると short *p = 0xdeadbeef; short x = *p; は未定義動作になるので「何が起きてもおかしくない」ということです. 変なデータが得られるかもしれないし, (時間がかかるだけで) 想定したデータが得られるかもしれないし, 異常終了しちゃうかもしれない. ということで, 「どんなシステムでも絶対確実に動かす」ということだと struct typeA { char a; union { struct { int s, t, u, v; }; struct { long x, y; }; }; }; として, 得られたデータをこの構造体に入れる (アンパックする) くらいしかないんじゃないかなぁ? もちろんこのようにすると処理時間やメモリが無駄になる (可能性がある) ので, 使うシステムが限定されていて「変更はありえない」ということであればさっさとキャストしてしまうという方針もあります. あとで何かあっても知らないけど. |
|---|---|
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| |
回答日時:08/04/09 13:59 回答番号:No.8 |
|
| この回答へのお礼 | 回答ありがとうございます。 今回、想定しているCPUは固定(MB91FV310A)ですので、「どんなシステムでも絶対確実に動かす」必要はありませんが、アドバイス感謝します。 |
回答 |
|
| 回答者:noocyte | > たとえばshort(2バイト)のデータが2の倍数のアドレスでないと > 「効率が悪い」のではなく、「動作しない」処理系があるということでしょうか? あります.(言語処理系ではなく,CPU の話ですが.) CPU を特定しないのなら,それが普通と考えるべきです. http://www5d.biglobe.ne.jp/~noocyte/Programming/Alignment.html |
|---|---|
| 種類:アドバイス どんな人:専門家 自信:自信あり |
|
| |
回答日時:08/04/09 12:38 回答番号:No.7 |
|
| この回答へのお礼 | 回答ありがとうございます。 想定しているCPUは固定なので、そのCPUで1度試してみます。 |
回答良回答10pt |
|
| 回答者:tadys | 処理系によってはshort(2バイト)データのアドレスが2の倍数、long(4バイト)データのアドレスが4の倍数でないと動作しないものがあります。 その場合、9バイトデータと、1バイト+2バイト*4と、1バイト+4バイト*2ではデータ構造が異なるのでunionで共存させる事はできません。 共存させる事が可能な処理系が有るかもしれませんが互換性の欠けたものになります。 例えば、 struct typeA { char a; short s,t,u,v;}; struct typeB { char a; long x,y}; とすると sizeof(typeA) は10、sizeof(typeB) は12となり9バイトデータとは適合しません。 sのアドレスは a+1 では無く、a+2になります。 xのアドレスは a+1 では無く、a+4になります。 コンパイラのオプションの設定によっては9バイトデータに適合させられるかもしれませんが処理速度が低下する恐れがあるのでお勧めできません。 現実的な解決策はstruct typeB { char a; long x,y};のデータに統一する事です。 struct typeAB{ char a ; /* long にしてもデータのサイズは変わらない */ union{ short s[4] ; long l[2] ; } ; } ; /* sizeof(typeAB) は12になります */ 9バイトにこだわるのであればバイト毎に取り出して別の変数に代入する方法になります。 |
|---|---|
| 種類:回答 どんな人:経験者 自信:自信あり |
|
| |
回答日時:08/04/09 09:58 回答番号:No.6 |
|
| この回答へのお礼 | 失礼ながら、皆様のお礼、まとめて書かせていただきます。 皆様、分かりやすい回答ありがとうございます。 アラインメントの問題がからんでくるため pa = p; pa->s でアクセスしてもだめな場合があるということ良く分かりました。 >現実的な解決策はstruct typeB { char a; long x,y};のデータに統一する事です。 以下の事情で教示いただいた解決策は使えません(悲)。 9バイトデータはgivenです。通信回線からの受信データを想定しています。バッファから1パケット分のデータを受け取り、それを加工するプログラムです。char *p は、これから処理すべきデータの先頭(パケットの先頭ではありません)を指しています。 ここで新たな疑問が発生しました。たとえばshort(2バイト)のデータが2の倍数のアドレスでないと「効率が悪い」のではなく、「動作しない」処理系があるということでしょうか? 引き続きよろしくお願いいたします。 |
回答 |
|
| 回答者:Oh-Orange | ★補足。 ・C言語だとタグ名を省略できないかも。 C++なら省略可能。 |
|---|---|
| 種類:アドバイス どんな人:専門家 自信:参考意見 |
|
| |
回答日時:08/04/09 00:15 回答番号:No.5 |
|
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| 回答者:Oh-Orange | ★アドバイス ・2バイトのデータ型をshort 4バイトのデータ型をlong として回答します。 サンプル1: short *pA; long *pB; char *p; p = (char *)data; ←9バイトのデータをセット if ( *p == 2 ){ ←2バイト×4個の場合 pA = (short *)(p + 1); } else if ( *p == 4 ){ ←4バイト×2個の場合 pB = (long *)(p + 1); } ・pA[0]〜pA[3]でアクセス pB[0]、pB[1]でアクセス サンプル2:共用体を利用 typedef struct tagDATA { char type; union { short word[4]; long dword[2]; }; } data_t; data_t *p = (data_t *)data; ←9バイトのデータをセット if ( p->type == 2 ){ ←2バイト×4個の場合 p->word[0] : p->word[3]をアクセス } else if ( p->type == 4 ){ ←4バイト×2個の場合 p->dword[0] : p->dword[1]をアクセス } ※回答者No.1さんはタグ名に ta、tb を使っていますが 共用体のタグ名を省略できます。 付けても問題ありません。 |
|---|---|
| 種類:回答 どんな人:専門家 自信:参考意見 |
|
| |
回答日時:08/04/09 00:07 回答番号:No.4 |
|
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| 回答者:koko_u_ | int が 2バイト で long が 4バイトとは限らないことにも注意した方がよいでしょう。 |
|---|---|
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| |
回答日時:08/04/08 23:06 回答番号:No.3 |
|
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| 回答者:asuncion | 余計なお世話でしたら聞き流してください。 int型の大きさは、いまどきのコンパイラでしたら たいていは4バイト以上だと思います。 2バイトの整数型を扱うのでしたら、shortと書かれる方が よいのではないかと思います。 また、アラインメントの問題がからんでくるために、 当該の2つの構造体の大きさが異なることが考えられると思います。 大きさをそろえるためにダミーの領域を用意する必要が 出てくるかもしれません。 |
|---|---|
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| |
回答日時:08/04/08 23:05 回答番号:No.2 |
|
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| 回答者:notnot | unionを使います。 インデントを残すために行頭に : を書いています。 :typedef struct { : char a; : union { struct {int s,t,u,v;} ta; : struct {long x,y;} tb; : }; :} typeAB; :typeAB *p; :p=(*typeAB)malloc(sizeof(typeAB)); :if(p->a=='?') { : sub1(p->ta.s); :}else{ : sub2(p->tb.x); :} |
|---|---|
| 種類:回答 どんな人:一般人 自信:自信あり |
|
| |
回答日時:08/04/08 22:27 回答番号:No.1 |
|
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |