プロが教えるわが家の防犯対策術!

構造体メンバーのカンマ区切り出力をしたいと思っています。

たとえば
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);
などのようにメンバー名(変数名)を参照せずに、構造体のメンバーへのポインタを順次取得しループして出力するなどして、実現することは可能でしょうか?

A 回答 (6件)

こんにちわ。



構造体のメンバー名を使用せずにポインタでアクセスする事は可能ですが、
移植性やメンテナンス効率が悪くなるので、通常はあまりやりません。
例えば例にある構造体で、
st *struct XXX;
となっていた場合、
strcpy(tel, ((char *)(st) + 60));
とすれば、tel メンバーにアクセスできます。

※ 構造体内に様々なデータ型を含む場合は、領域が獲得される領域が
  整列されるため、構造体内のオフセットの計算に注意する必要が
  あります。

以前使っていたマクロですが、
#defineSTOFFSET(st ,member)((long)(&((st *)0)->member))
と宣言して、

printf("Offset (tel) = %d\n", STOFFSET(struct XXX, tel));
とすれば、メンバー内のオフセットを計算できます。
参考にして下さいね。
    • good
    • 0
この回答へのお礼

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

いただいた情報を元にさらに調べたところ、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;


として得られる。
--

お礼日時:2002/11/13 10:48

構造体のメンバーをポインタにできるのなら比較的楽ですね。


以下のように union にしてもよいですし、無理矢理 cast しちゃってもよいですし。
union uXXX {
 struct XXX {
  char *name;
  char *address;
  char *tel;
   :
 }
 char* aaa[100];
};
    • good
    • 0
この回答へのお礼

どうもありがとうございます!

残念ながら、構造体は私が設計したものではないので、いじれないのです。 (;_;

これ、おもしろいですね!
参考にさせていただきます。ありがとうございます。

お礼日時:2002/11/29 22:50

なんかそもそもそのような構造体を作ること自体の設計に問題がありそうですけど。



もし、メンバーが全部char ならば(つまり同一という意味)、

struct XXX {
char *member[100];
} s;

enum {_name, _address, _tel, ...} index;

として、

s.member[_name] = "namae";
....
そして、まとめて取り扱うときには、
index = 0;
s.member[index]

のようにするのが普通と思います。

いかがでしょう?
    • good
    • 0
この回答へのお礼

どうもありがとうございます!

残念ながら、構造体は私が設計したものではないので、いじれないのです。
どうもありがとうございます。

教えていただいた方法というのもありですね。
どうもありがとうございます。

お礼日時:2002/11/29 22:47

ああ、ごめんなさい。


よく読んでませんでした。

メンバをポインタ経由で参照するということですよね?

可能です。が、やはりお薦めできません。

他の方がおっしゃっているように移植性の問題やらが大変なので一つ一つのメンバにアクセスした方が結果的にラクです。

この回答への補足

いえいえ、とんでもないです。ありがとうございました。

補足日時:2002/11/29 22:20
    • good
    • 0

いっそのこと構造体を 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;
}

*************************************************

これなら動的に確保することも容易ですし。
    • good
    • 0
この回答へのお礼

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

恐れ入りますが、構造体のインスタンス?(コピー)が多いのではなく、あくまで「メンバー」が多いので、メンバー名を使用したくないのです。

よろしくお願いします。

お礼日時:2002/11/13 10:50

offsetofで構造体の先頭からのバイト数取得し、あらかじめ配列に格納しておいて、それをループでまわすというのは?



もちろん、intなんかが混じってたら別の方法を考えないとダメでしょうけど。
    • good
    • 0
この回答へのお礼

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

こんな演算子があったのですね?と思ったら、ちょっと調べてみたところマクロなのですね。知りませんでした。

活用して工夫してみます。ありがとうございます。

お礼日時:2002/11/13 10:44

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!