C言語関係掲示板

過去ログ

No.392.構造体の項目をメンバ参照せずに取り出すには?

[戻る] [ホームページ]
No.2696

構造体の項目をメンバ参照せずに取り出すには?
投稿者---ミヤモト(2002/09/13 13:15:08)


こんにちは。

DBからバッファの構造体に落としたデータを
ファイルに書き出したいと思っています。
その際、

項目|項目|項目|・・・

このように項目の後ろに縦棒をつけて書き出したいのですが、
strcatを使って、ひとつづつ項目の後に縦棒を連結させるとなると、
項目数が100を越すものもあるので、ソースを書くのが大変になってしまいます。
メンバ参照せずに、項目を取り出す方法はあるのでしょうか?
項目に番号を付けて(構造体.1) などとできるのでしょうか?
項目にはVarcharのものもDecimalなものも入っています。

よろしくお願いいたします。


No.2699

Re:構造体の項目をメンバ参照せずに取り出すには?
投稿者---kikk(2002/09/14 04:20:25)


ども。


>DBからバッファの構造体に落としたデータを
>ファイルに書き出したいと思っています。

えと、テキストで書き出せばいいのでしょうか?
そう仮定して、以下のようなのを考えてみました。どうでしょうか。
一部のメンバだけを書き出すのにはもう一工夫いります。

まず、以下の形式のレコードファイル(rec.def)を用意。
構造体定義またはDBのレコード定義がすでにできているのであれば、
適宜スクリプトを書いて変換生成するなどしてください。

#define NA

/* type, var_name, length, output_format */
MEMBER_DEF(int, i1, NA, "%d")
MEMBER_DEF(int, i2, NA, "%08x")
MEMBER_DEF(char, c1, NA, "%c")
MEMBER_DEF(char, s1, [10], "%s")

#undef NA

で、Cソースでの構造体定義は以下のようになります。

struct Rec {
#define SYMCAT(X,Y) X##Y
#define MEMBER_DEF(T,V,L,F) T SYMCAT(V,L);
#include "rec.def"
#undef SYMCAT
#undef MEMBER_DEF
};

また、出力は以下のようにします。buf[]は十分な長さがあるとします。
エラーチェックは省略(pとbufの差をとれば可能)。またrec.defは空でない
と仮定。

char buf[N],*p;
p=buf;
#define MEMBER_DEF(T,V,L,F) p+=sprintf(p, F "|", rec.V);
#include "rec.def"
#undef MEMBER_DEF
*(--p)='\0';
fprintf(fp, "%s\n", buf);


なお、レコードの構成が変わった場合はrec.defを書き換えればOKです。

単純に出力部をスクリプトで自動生成した後、#includeするほうが
楽な気がしないでもないですが。。


では。

No.2701

Re:構造体の項目をメンバ参照せずに取り出すには?
投稿者---Cman(2002/09/14 18:47:01)


ところで質問するけど。
例えば

typedef struct{
int a;
int b;
int c;

}x;
.
.
.
x staff[] = {{0},{0},{0}};

で構造体の中身を書き換えようとする時、getsなどで[1]の部分を書き換えて書き換えたいとこを変えれるけど、aの部分をgetsなどで書き換えて、同じようなことが出来ないものだろうか?

 staff[1].a = 3;

for(crSf=0;crSf<styouso;crSf++)
{
printf("%d %d %d %d\n",crSf+1, staff[crSf].a,
     staff[crSf].b,staff[crSf].c);
}





No.2703

Re:構造体の項目をメンバ参照せずに取り出すには?
投稿者---kikk(2002/09/14 23:15:15)


ども。


>で構造体の中身を書き換えようとする時、getsなどで[1]の部分を書き換えて書き換えたいとこを変えれるけど、aの部分をgetsなどで書き換えて、同じようなことが出来ないものだろうか?
>
> staff[1].a = 3;

構造体のメンバを文字列で引きたいということでしょうか?

同じような方法でやる場合は、

/* rec.def */
/* ここでは配列については省略(必要ならば前の書き込みを参照) */
MEMBER_DEF(int, a)
MEMBER_DEF(int, b)
MEMBER_DEF(int, c)

とし、

/* 構造体宣言部 */
struct Rec {
#define MEMBER_DEF(T,V) T V;
#include "rec.def"
#undef MEMBER_DEF
};

/* 処理部 */
/* member_nameはメンバ名の文字列 */
{
#define MEMBER_DEF(T,V) \
else if (!strcmp(member_name, #V)) {\
staff.##V = 3;\
};
if (0) {}
#include "rec.def"
#undef MEMBER_DEF
}

比較部の高速化が必要ならばgperfをmakeに仕込む等してください。
文字列ではなく、構造体のn番目のメンバ、という方法でアクセスするので
あれば、もう少し速くならなくもないですが。。

やりたいことがちがってたらごめんなさい。


では。

No.2723

Re:構造体の項目をメンバ参照せずに取り出すには?
投稿者---ミヤモト(2002/09/17 17:28:06)


こんにちは。
質問したミヤモトといいます。
回答ありがとうございました。
私は超のつくCの初心者です。なので分からない部分があってもう一度質問します。

ファイルの書き出しはテキストで行います。

struct Rec {
#define SYMCAT(X,Y) X##Y
↑ここはXとYという2つのトークンを結合して

#define MEMBER_DEF(T,V,L,F) T SYMCAT(V,L);
↑ここではなにを行っているのでしょうか。

またマクロ定義を#undefで 未定義状態に戻しているのは
なにのためでしょうか。

回答よろしくお願いいたします。

No.2726

Re:構造体の項目をメンバ参照せずに取り出すには?
投稿者---かずま(2002/09/17 23:21:03)


> ファイルの書き出しはテキストで行います。

ファイルに書き出すのなら、strcat や sprintf で文字列を char buf[N] に
書き込まなくて済みますね。次のように書くと、トークンの結合は不要です。
#define MEMBER が 2つあるので、最低 1つは #undef MEMBER が必要です。
#include <stdio.h>

#define MEMBERS_DEF \
    MEMBER(int,    m1,   NA, "%d|"  ) \
    MEMBER(int,    m2,   NA, "%08x|") \
    MEMBER(char,   m3,   NA, "%c|"  ) \
    MEMBER(char,   m4, [16], "%s|"  ) \
    MEMBER(char *, m5,   NA, "%s\n" ) \

typedef struct {
    #define NA
    #define MEMBER(type, member, size, format) type member size;
    MEMBERS_DEF
} Rec;

void printRec(FILE *fp, const Rec *rp)
{
    #undef MEMBER
    #define MEMBER(type, member, size, format) fprintf(fp, format, rp->member);
    MEMBERS_DEF
}

int main()
{
    Rec rec = { 123, 0x80abcdef, 'A', "abcdef", "xyz" };
    printRec(stdout, &rec);
    return 0;
}