- ベストアンサー
[C] 構造体メンバーのカンマ区切り出力
構造体メンバーのカンマ区切り出力をしたいと思っています。 たとえば struct XXX { char name[20]; char address[40]; char tel[12]; ... 100メンバーくらいある } のような構造体があったとします。 printf("%s,%s,%s\n", s_ptr->name, s_ptr->address, s_ptr->tel); などのようにメンバー名(変数名)を参照せずに、構造体のメンバーへのポインタを順次取得しループして出力するなどして、実現することは可能でしょうか?
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
こんにちわ。 構造体のメンバー名を使用せずにポインタでアクセスする事は可能ですが、 移植性やメンテナンス効率が悪くなるので、通常はあまりやりません。 例えば例にある構造体で、 st *struct XXX; となっていた場合、 strcpy(tel, ((char *)(st) + 60)); とすれば、tel メンバーにアクセスできます。 ※ 構造体内に様々なデータ型を含む場合は、領域が獲得される領域が 整列されるため、構造体内のオフセットの計算に注意する必要が あります。 以前使っていたマクロですが、 #define STOFFSET(st ,member) ((long)(&((st *)0)->member)) と宣言して、 printf("Offset (tel) = %d\n", STOFFSET(struct XXX, tel)); とすれば、メンバー内のオフセットを計算できます。 参考にして下さいね。
その他の回答 (5)
- yatokesa
- ベストアンサー率40% (201/496)
構造体のメンバーをポインタにできるのなら比較的楽ですね。 以下のように union にしてもよいですし、無理矢理 cast しちゃってもよいですし。 union uXXX { struct XXX { char *name; char *address; char *tel; : } char* aaa[100]; };
お礼
どうもありがとうございます! 残念ながら、構造体は私が設計したものではないので、いじれないのです。 (;_; これ、おもしろいですね! 参考にさせていただきます。ありがとうございます。
なんかそもそもそのような構造体を作ること自体の設計に問題がありそうですけど。 もし、メンバーが全部char ならば(つまり同一という意味)、 struct XXX { char *member[100]; } s; enum {_name, _address, _tel, ...} index; として、 s.member[_name] = "namae"; .... そして、まとめて取り扱うときには、 index = 0; s.member[index] のようにするのが普通と思います。 いかがでしょう?
お礼
どうもありがとうございます! 残念ながら、構造体は私が設計したものではないので、いじれないのです。 どうもありがとうございます。 教えていただいた方法というのもありですね。 どうもありがとうございます。
- HogePiyo
- ベストアンサー率57% (24/42)
ああ、ごめんなさい。 よく読んでませんでした。 メンバをポインタ経由で参照するということですよね? 可能です。が、やはりお薦めできません。 他の方がおっしゃっているように移植性の問題やらが大変なので一つ一つのメンバにアクセスした方が結果的にラクです。
補足
いえいえ、とんでもないです。ありがとうございました。
- HogePiyo
- ベストアンサー率57% (24/42)
いっそのこと構造体を typedef で型にしてからその配列にアクセスするという方法はどうです? ************************************************* #include <stdio.h> typedef struct { int hoge; int piyo; char name[64]; } DATA; int main(void){ int i; DATA data[] = { { 10, 20, "hoge" }, { 20, 30, "piyo" }, { 30, 40, "name" } }; for( i = 0; i < 3; i++ ){ printf( "%d,%d,%s\n", data[i].hoge, data[i].piyo, data[i].name ); } return 0; } ************************************************* これなら動的に確保することも容易ですし。
お礼
ご回答ありがとうございます。 恐れ入りますが、構造体のインスタンス?(コピー)が多いのではなく、あくまで「メンバー」が多いので、メンバー名を使用したくないのです。 よろしくお願いします。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
offsetofで構造体の先頭からのバイト数取得し、あらかじめ配列に格納しておいて、それをループでまわすというのは? もちろん、intなんかが混じってたら別の方法を考えないとダメでしょうけど。
お礼
ご回答ありがとうございます。 こんな演算子があったのですね?と思ったら、ちょっと調べてみたところマクロなのですね。知りませんでした。 活用して工夫してみます。ありがとうございます。
お礼
ご回答詳細にありがとうございます。 いただいた情報を元にさらに調べたところ、taka_tetsu様のご回答の“からくり”の部分に相当することなのですね。 いただいた情報から更に検索すると下記の情報も得られました。 どうもありがとうございました。 --<C FAQ>-- 2.14: 構造体内のフィールドのバイトオフセットを知る方法は。 A: ANSI Cは、offsetofマクロを用意しているので、用意されている場合 は使うこと。<stddef.h>を参照。もし手に入れることができなければ、 実装の一つは以下のようになる。 #define offsetof(type, mem) ((size_t) \ ((char *)&((type *)0)->mem - (char *)(type *)0)) この実装も100%の移植性を持つわけではない。コンパイラの中には、 はねつけるものがあるかもしれないが、それはそれで文法的に正しい。 次の質問2.15への解答を、使い方の参考にすること。 References: ANSI Sec. 4.1.5; ISO Sec. 7.1.6; Rationale Sec. 3.5.4.2; H&S Sec. 11.1 pp. 292-3. -------------------------------------------------------------------------------- 2.15: どうやれば構造体のフィールドを、実行時に名前でアクセスできるか。 A: まずoffsetof()マクロを使って名前とオフセットの対応表を用意する。 構造体aのフィールドbのオフセットは、 offsetb = offsetof(struct a, b) で与えられる。もし以下の式でstructpが、構造体の実体へのポイン ターで、bが上で計算したオフセットを持つintのフィールドとすると、 bの値は間接的に *(int *)((char *)structp + offsetb) = value; として得られる。 --