• ベストアンサー

C言語で構造体のメンバを簡単に出力する方法ありますか?

いつもお世話になっています。 C言語の質問です。 単体テストログを取るために、 “関数Aをコールする前後で、関数Aに引数として渡す構造体のメンバをすべて”printf(もしくはfprintf)で出力して比較確認しなければならないのですが、 構造体のメンバが250とか、150とかあり、メンバ名もxxx_01,xxx_02などのようにエクセルなどで簡単に加工して作れるものではないので、いちいちメンバ名を指定しなければならないのでとても大変です。 オブジェクト指向言語なら、for each文とかでオブジェクトのメンバを簡単に取り出せるのでしょうが(間違っているかもしれません・・・)、C言語で構造体のメンバを、for文などのループを使って簡単に出力できる方法はないでしょうか? メンバの型は、一定ではなく、char、int、double、別の構造体のポインタ型(これは出力しなくて良い)と混在しています。メンバが全て同一の型ならポインタで構造体の先頭アドレスからsizeof(メンバの型)の分インクリメントしていけば出力できそうな気もしますが、メモリ上に連続して確保されるのかも私にはわからないので困っています。 enumで列挙して・・・というのも調べてみましたが、応用は出来ないようでした。 どなたか、地道にメンバ名を書いて出力する以外の方法をご存知の方、いらっしゃいましたらお知恵をお貸しください。 よろしくお願いいたします。 ※説明不足の点がありましたら補足いたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • salsberry
  • ベストアンサー率69% (495/711)
回答No.5

コードを書かないという方向性の提案を一つ。 デバッガに構造体の内容を出力させるというのはどうでしょうか。 struct { int a; char *b; double c; } という型を持つ変数xがあったとして、gdbでは下記のような出力が得られます。 (gdb) print x $1 = { a = 123, b = 0x2fd0 "ABC", c = -9876.5 }

miraise
質問者

お礼

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

miraise
質問者

補足

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

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (4)

  • ko_kinta
  • ベストアンサー率39% (43/109)
回答No.4

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

全文を見る
すると、全ての回答が全文表示されます。
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

こんなのはどうでしょう? #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マクロの定義状態によって、構造体の定義とダンプ用の関数を生成できるはずです。

miraise
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
  • ko_kinta
  • ベストアンサー率39% (43/109)
回答No.2

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で読み込むという手間がかかるかな。

miraise
質問者

お礼

ご回答ありがとうございます。 家庭内で不慮の悲しい出来事があり御礼が遅れてしまい申し訳ありません。 エクセルで加工するのが便利ですね。 ただ、行数が多くなってしまうのでうまくいかないものかな・・・(ループ文とかで短いコードで処理)と思い質問させていただきました。 sakuraエディタは出向先の意向により使用できない(同じく矩形選択できるemエディタなども使用できない、使用できるのは秀丸のみ)なので矩形選択ができないのがつらいところです。

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

そんな便利機能はないので、地道に書くしかありません。 いっそ「構造体の定義を解析してprintf()に変換する」プログラムを書いてしまうのが楽かもしれませんね。 しかしメンバーが100超えって……も少しコンパクトな単位に分けられなかったんでしょうか? for eachにしても例外はあるかもしれませんが「配列の各要素を先頭から終端まで」なので構造体メンバーの取得には使えません。

miraise
質問者

お礼

ご回答ありがとうございます。 帰宅が遅くなってしまいましたので、とりあえず#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言語に存在しないのでマシン語に近い高級言語とはこういうものかと、良くも悪くもよい経験をさせてもらっています。 私の開発効率が低く、休日出勤になってしまいそうで皆様へのお返事は遅れてしまうかもしれませんが、必ずお返事はいたしますのでしばらくお待ちいただけますようお願いいたします。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

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

  • Cで関数とポインタと構造体の表現法

    C言語の関数で 構造体・共用体の入った配列を関数にポインタで送りたいと思うのですが上手くいきません プロトタイプ宣言とメイン文での表現・関数そのものでの表現 が詳しく知りたいのですがサイトまたは記述方を教えてください。 上記の条件で ポインタは*をつけるつけない 関数で引数はどうやって選ぶのか 構造体名などはどのように表現すればいいのか などの見分けがいまいちつかないので悩んでいます。

  • 構造体変数がないとメンバ操作できないのはなぜ?

    C言語の構造体に関して質問がありますが、structで型を作成して、構造体変数にてメンバの代入・参照をする。ということなんですが、なんでメンバ操作には構造体変数からでないといけないのでしょうか? 直接、型枠にてメンバ操作をすれば良いのに、なぜ構造体変数から操作しないといけないのでしょうか? 「クラス」や「オブジェクト」みたいに、一々ゼロから作成したり、コピペで作成しなくても済むように、このような形になっているのでしょうか? 回答の方よろしくお願いします。

  • C言語(c++)の構造体

    プログラミング(c++)の本に書いてあった問題の答えが分かりません。 課題 実部(実数)と虚数(実数)をメンバとして持つ複素数型(構造体)を定義し、複素数の四則演算を行う関数をそれぞれ定義してその動作を確認せよ どなたか答えを教えてください 本に書いてあるのでプログラミングの基本はわかるのですが自分で組むとコンパイルに失敗します 「構造体とポインタ」という章の問題なのでそれを踏まえてお願いします

  • C言語のvoid型ポインタを使いたいのですが…

    C言語のvoid型ポインタを使いたいのですが… 関数の引数として、void型ポインタを使おうと思ったのですが、内部でどのように処理すればいいのかわかりません キャストすれば問題なく使えるとのことですが、どの型でキャストするのかをどのように判断するのかがわかりません 具体的には、画像処理で画像の構造体をいくつか作ったのですが、それぞれの構造体ごとに関数を書くと関数が多くなるので、void型ポインタでまとめてつくろうとしています どのように型の判断を行えばいいのかを教えてください

  • C++では構造体がメンバ関数をもてることについて

    仕事ではC言語を使っています。7年ぶりくらいにC++を勉強しなおす気になりました。勉強し始めて疑問に思ったことがあります。 C++では構造体もメンバ関数やコンストラクタ、デストラクタをもてるようですが、なぜそのような仕様になったのでしょうか?クラスでできることをわざわざ構造体(や共用体)でも出来る必要性を感じません。(きらいなら使わなければいいだけのことですが。) 学生時代にC++を勉強したとき使っていた本(※)にそのような記述が無かったような気がします。 ※柴田望洋著:プログラミング講義C++、ソフトバンクブックス、1997 なぜそのような仕様になっているのか、経緯や必要性について教えてください。

  • C言語構造体についてです。

    C言語、π=PI 3.14159265で構造体を用いてmensekiを呼び出して 半径と面積を計算して出力するプログラムです。下の空白を埋めてもらえますか? /* 構造体のプログラム */ #include <stdio.h> #include <math.h> #define PI 3.14159265 struct Data { /* 半径rと面積areaをdoubleで宣言 */ }; void menseki(struct ... 構造体のポインタを引数とする ){ /* 面積を計算する際に構造体のアドレスから計算する */ circle->area=PI* .....; } main(){ struct Data example[2]; //構造体配列 int i; /* 半径rを構造体配列を用いて2例入力する */ /* 2例の各々について mensekiを呼び出して 半径と面積を計算して出力する */ } よろしくお願いします。

  • C言語の構造体についてなんですが。

    struct LIST {     struct Num* number;     struct LIST* next;/* 次の要素へのポインタ */ }*root; struct Num{     int a;     struct Num* next; /* 次の要素へのポインタ */ }*numroot; と構造体を定義したときに、 main(){     struct LIST *p;     for(p = root; p != NULL; p = p->next) ; } とすれば、pの先頭からNULLまでを参照していくことは分かるんですが、pのnumberの先頭からNULLまでの参照方法(プログラムのfor文の記述方法)がイマイチわかりません。つまり、構造体の構造体をどのように参照するかということです。 これを実現したい理由は、構造体内での数の格納を配列(固定長)ではなく可変長で格納したいからです。 分かる方は解答をお願いします。

  • C言語 構造体

    商品番号no、商品名name、仕入れ価格k1、販売価格k2、利益riの5つのメンバからなる構造体syouhinを作成し、noからk2までのデータを入力、riを求め結果として構造体の5つのメンバを出力しなさい。データはデータファイルを作成し読みこむこととし、商品数は数個与えなさい。 という問題なのですがよく分かりません。 プログラムを教えてください。 よろしくお願いします。

  • C言語、構造体の値を比較する関数

    C言語で組み込み系ソフトを作っています。 初心者です。 下記の型違いのデータを100バイト含んだ構造体があったとします。 そのデータを1バイトずつ所定の範囲内か確認して、 範囲内ならTRUE、外ならFALSEを返す関数を作りたいです。 どうな風に記述してよいかわかりません。 イメージ的には、  データ(mydt)のポインタを引数で渡して  関数内で1バイトずつ所定の範囲内か確認したいです。 データが100個もあるので1個1個変数名と範囲を書いて比較するのは大変です。 ややこしいのが、構造体に型が違うものが入っているので何バイト目のデータが サインドなのかアンサインドなのか識別しないといけないです。 何か良い関数もしくは構造体の記述方法があればお願いします。 //-記- //構造体 struct stdata_tag{ uint8_t run_time; // 0バイト目 運転時間 0~99 int8_t melt_temp; // 1バイト目 融解温度 -10~20 uint8_t cmonbaby; // 2バイト目 家紋赤子 0~2 int8_t cold_temp; // 3バイト目 高温温度 -50~10 : : uint8_t damage; //99バイト目 ダメージ 1~255 } //構造体実態を確保 struct stdata_tag mydt;