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

いつもお世話になっています。

C言語の質問です。
単体テストログを取るために、
“関数Aをコールする前後で、関数Aに引数として渡す構造体のメンバをすべて”printf(もしくはfprintf)で出力して比較確認しなければならないのですが、

構造体のメンバが250とか、150とかあり、メンバ名もxxx_01,xxx_02などのようにエクセルなどで簡単に加工して作れるものではないので、いちいちメンバ名を指定しなければならないのでとても大変です。

オブジェクト指向言語なら、for each文とかでオブジェクトのメンバを簡単に取り出せるのでしょうが(間違っているかもしれません・・・)、C言語で構造体のメンバを、for文などのループを使って簡単に出力できる方法はないでしょうか?

メンバの型は、一定ではなく、char、int、double、別の構造体のポインタ型(これは出力しなくて良い)と混在しています。メンバが全て同一の型ならポインタで構造体の先頭アドレスからsizeof(メンバの型)の分インクリメントしていけば出力できそうな気もしますが、メモリ上に連続して確保されるのかも私にはわからないので困っています。

enumで列挙して・・・というのも調べてみましたが、応用は出来ないようでした。

どなたか、地道にメンバ名を書いて出力する以外の方法をご存知の方、いらっしゃいましたらお知恵をお貸しください。
よろしくお願いいたします。
※説明不足の点がありましたら補足いたします。

A 回答 (5件)

コードを書かないという方向性の提案を一つ。


デバッガに構造体の内容を出力させるというのはどうでしょうか。

struct {
int a;
char *b;
double c;
}
という型を持つ変数xがあったとして、gdbでは下記のような出力が得られます。
(gdb) print x
$1 = {
a = 123,
b = 0x2fd0 "ABC",
c = -9876.5
}

この回答への補足

gdbは、プロジェクト方針で「使用しない」とのことですが、インストールはされていたので使用してみました。思っていたほど難しくなく、デバッグがとても便利になりました。大変役に立つアドバイスありがとうございました。

補足日時:2008/12/19 12:07
    • good
    • 1
この回答へのお礼

ご回答ありがとうございます。
家庭内で不慮の悲しい出来事があり御礼が遅れてしまい申し訳ありません。

gdbは導入しておらず(なぜ?)、他にメモリリーク検出のvalgrindなども導入されていないので使用できませんでした。
私自身gdbは名前を知っている程度でしたので、このような使い方が出来るとは知りませんでした。勉強してみたいと思います。
大変参考になる意見ありがとうございました。

お礼日時:2008/12/12 16:41

#2です。


cvsはcsvの誤りです。
メンバ型はB列にしましたが、最右列にしておけば加工後に列削除や非表示にしなくても選択するときに除くことができます。
やりやすいようにどうぞ。
    • good
    • 0

こんなのはどうでしょう?



#ifdef DUMP
# define STRUCT(name) void dump_##name(const struct name *data, FILE *stream) {
# define END_STRUCT }
# define MEMBER(type, name) print_##type(data->name);
#else
# define STRUCT(name) struct name {
# define END_STRUCT };
# define MEMBER(type, name) type name;
#endif

といったマクロを定義しておいて、

STRUCT(foo)
MEMBER(int, hoge)
MEMBER(double, bar)
...
END_STRUCT

のようにすれば、DUMPマクロの定義状態によって、構造体の定義とダンプ用の関数を生成できるはずです。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
家庭内で不慮の悲しい出来事があり御礼が遅れてしまい申し訳ありません。

マクロは確かに便利そうですね。
マネージャに相談してみたのですが「可読性が低くなる」とのことで却下されてしまいました。。
せっかくお答えいただいたのに申し訳ありません。
今後の参考にさせていただきます。

お礼日時:2008/12/12 16:38

excelにメンバの型とメンバ名だけをコピーしてから加工→エディタにコピーすればそんなに手間じゃないですよ。



excel側
A列:「printf("」
B列:メンバ型をコピー
C列:メンバ名をコピー
D列:「=if(B1="char *", " %s", if(B1="double", " %lf", " %d"))」
E列:「\n", XXX.」(XXXは構造体変数名)
F列:「=C1」
G列:「);」

A、D~G列をオートフィルでメンバ行数分コピーしたらB列を削除するか非表示にして全選択し、エディタに貼り付けします。
エディタ側では列と列の間がタブで区切られているので、置換機能でタブを削除すればメンバが200でも1000でもあっと言う間に出力文完成。
こんな風。
printf("memb1 %s\n", XXX.memb1);
printf("memb2 %lf\n", XXX.memb2);


windowsだったらsakuraエディタのように矩形選択が使えるエディタならメンバ型、名をexcelにコピーするのも楽ですね。
矩形選択が出来ないのならcvsにしてからexcelで読み込むという手間がかかるかな。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
家庭内で不慮の悲しい出来事があり御礼が遅れてしまい申し訳ありません。

エクセルで加工するのが便利ですね。
ただ、行数が多くなってしまうのでうまくいかないものかな・・・(ループ文とかで短いコードで処理)と思い質問させていただきました。

sakuraエディタは出向先の意向により使用できない(同じく矩形選択できるemエディタなども使用できない、使用できるのは秀丸のみ)なので矩形選択ができないのがつらいところです。

お礼日時:2008/12/12 16:37

そんな便利機能はないので、地道に書くしかありません。


いっそ「構造体の定義を解析してprintf()に変換する」プログラムを書いてしまうのが楽かもしれませんね。

しかしメンバーが100超えって……も少しコンパクトな単位に分けられなかったんでしょうか?

for eachにしても例外はあるかもしれませんが「配列の各要素を先頭から終端まで」なので構造体メンバーの取得には使えません。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
帰宅が遅くなってしまいましたので、とりあえず#1様の欄に返信させていただきます。
#2~#5の方につきましても、後日回答をさせていただきます。
まことに勝手で申し訳ありませんが、ご了承ください。

回答ですが、やはりそのような便利機能はありませんか。
今は、複数ある構造体ごとにそれぞれのメンバを出力する専用関数を作ろうかと考えています。

システムは金融系なのですが、DBのテーブルのカラムをコピーしてExcel2003に貼り付けたら、長すぎて貼り付けられませんでしたので、カラム数だけでExcelの横幅256項目を超えているようです。

構造体もネストの嵐で、ポインタを*、ダブルポインタを**で書くと、
引数として受け取る*構造体Aのメンバに*構造体Bと構造体Cがあり、
*構造体Bのメンバには構造体D配列があり、構造体D各々のメンバに構造体Eがある。
構造体Cのメンバには構造体Fがある。
そして関数には構造体Aの配列として**構造体A配列が渡される・・・
のような(私にはもう何がなにやら・・・の)つくりになっています。
それぞれ、メンバ数は30~250以上とさまざまです。

金融系のシステムって、こんなにデータ使うのか・・・と驚愕している次第です。。
古いシステムのようで、COBOLをC言語でラッパしているようです。
私としては、オブジェクト指向言語で作ればもっと扱いやすくなるのではないか・・・と考えているのですが、なにぶんこの金融危機でお金がないらしくコストのかかる開発はできないようです。

私は元々はVB系(の後にJava経験多少アリ)でしたので、Join関数やSplit関数、LBound関数、UBound関数、Redim関数・・・使い慣れていたものがことごとくC言語に存在しないのでマシン語に近い高級言語とはこういうものかと、良くも悪くもよい経験をさせてもらっています。

私の開発効率が低く、休日出勤になってしまいそうで皆様へのお返事は遅れてしまうかもしれませんが、必ずお返事はいたしますのでしばらくお待ちいただけますようお願いいたします。

お礼日時:2008/11/28 03:25

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

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A