K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[2222] ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:Hiroyuki Naito
2020/01/26 08:29:45

お世話になります。 細かいことで恐縮ですが、Fig2-10で「"&d, %s\n"へのポインタ」とありますが、「"%d, %s\n"へのポインタ」の誤植と思われます。 私が使っているCコンパイラはgcc 5.4.1 c99でしたので、p128で紹介されている__VA_ARGS__を以下のように使ってみました。 void debug_write(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #define DEBUG_WRITE(...) debug_write(__VA_ARGS__) でもちろん動作OKでしたが、 #define DEBUG_WRITE(...) fprintf(stderr, __VA_ARGS__) でもokでした。 「debug_write()関数の呼び出しのオーバーヘッドは避けられない(p127)」ということでしたが、fprintf()関数でも同様でしょうか。 〈使用例〉 int i = 300; char *p = "hoge"; DEBUG_WRITE("%s %d\n", p, i); また、 #define SNAP_INT(arg) fprintf(stderr, #arg "...%d", arg) の中の#argは引数名そのものを指しているようですが、(他のC言語の解説書では)見たことのない使い方でした。できましたら、補足説明をお願いいたします。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2223] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:Hiroyuki Naito
2020/01/26 09:40:19

お世話になります。 3番目の質問については、本文の「原理はプリプロセッサのマニュアルを調べよ」にヒントを得て調べてみたら、自己解決しました。 >#define SNAP_INT(arg) fprintf(stderr, #arg "...%d", arg) >の中の#argは引数名そのものを指しているようですが、(他のC言語の解説書では)見たことのない使い方でした。できましたら、補足説明をお願いいたします。 「#演算子は、マクロ実引数を文字列化します」ということでした。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2224] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:(ぱ)こと管理人
2020/01/26 23:15:21

>細かいことで恐縮ですが、Fig2-10で「"&d, %s\n"へのポインタ」とありますが、 >「"%d, %s\n"へのポインタ」の誤植と思われます。 ご指摘ありがとうございます。ミスが多くて申し訳ありません。 この部分は旧版から変えていないところなので、旧版から20年間発覚しなかった ミスかと旧版の正誤表を確認したところ、どうも旧版は ・%dであるべきところが&dになっている ・\nが抜けている というふたつのミスがあり、前者に気づいていながら後者だけ直していたようです。 http://kmaebashi.com/seiha/seigo.html#p102 何が何だか……(後ほど直します) >#define DEBUG_WRITE(...) fprintf(stderr, __VA_ARGS__) >でもokでした。 >「debug_write()関数の呼び出しのオーバーヘッドは避けられない(p127)」という >ことでしたが、fprintf()関数でも同様でしょうか。 読み返すと確かにわかりにくいのですが、 「debug_write()関数の呼び出しのオーバーヘッドは避けることができません。」 という記述は、いわゆるANSI C(C90)についての記載と思ってください。 そのすぐ下に、「マクロなら、コンパイル時に完全に抹殺できるのですが、 ANSI Cまでは、マクロには、可変長引数を渡すことができませんでした。」 とあるとおりです。 ただその下で、 | C99ではマクロが可変長引数を取ることができるようになったので、 | 以下のように書けるようになりました。 と書いておきながら、わざわざdebug_write()を呼んでいるのはちょっといただけないですね… (わずかばかりのオーバーヘッドを考えるより、出力先をまとめて切り替えたり タイムスタンプを足したりする利便性を考えて、私なら、実際にはdebug_write()を 挟みそうな気がしますし、そういう思いだったのかと思いますが) 何かしら補足を考えます。ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2225] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:(ぱ)こと管理人
2020/02/01 23:26:52

あれっ、何か妙なことを書いていました。 >ただその下で、 >| C99ではマクロが可変長引数を取ることができるようになったので、 >| 以下のように書けるようになりました。 > >と書いておきながら、わざわざdebug_write()を呼んでいるのはちょっといただけないですね… C99なら可変長引数のマクロが使えるので、コンパイル時に完全に抹殺できます。 よって、fprintf()を呼んでももちろん良いですが、debug_write()を呼んでも 消えてなくなるので別段「ちょっといただけない」こともないですね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2226] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:774RR
2020/02/04 07:08:55

ああツッコミてー printf() の実装は実際のところ 2222 の debug_write() と全く同じことが多くて、 よって printf() のクロック数と debug_write() のクロック数は全く同じで、 ついでに言うと printf() の処理中、文字化に要するクロック数と関数呼び出しクロック数では 後者は無視できるほど小さいっす。 さらに追加すると標準出力へ出力する際の実処理のクロック数のほうがもっと多い。 ボトルネックでないところのクロック数を頑張って減らしても全体の速度は大差ない。 というわけで debug_write() を真に関数として実装して増えるのはプログラムバイト数だけ debug_write() の命令語数の分、せいぜい数十バイト、実行クロック数は同一 なのでこんなところに労力使うくらいなら、別のところでもっと有意義に使いたいっす。 C/C++ ユーザーは実行時クロックを1クロックでも減らしたがるけど、悪い癖っす。 まあ組み込み系だとその数クロック数バイトが重要だったりしますが・・・
[この投稿を含むスレッドを表示] [この投稿を削除]
[2227] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:(ぱ)こと管理人
2020/02/05 23:13:49

>printf() の実装は実際のところ 2222 の debug_write() と全く同じことが多くて、 >よって printf() のクロック数と debug_write() のクロック数は全く同じで、 まず、「ポインタ完全制覇」での記載は、 #ifdef DEBUG printf(表示したい内容); #endif という方法を 「こんなものをソース中に大量に埋め込んだら、読みにくくてしょうがありません。」 と書いたうえで、vfprintf()を使ったdebug_write()を紹介しています。 つまりdebug_write()の比較対象は、printf()ではなく、 #ifdefを使った完全に抹殺できるデバッグライトです。 >ついでに言うと printf() の処理中、文字化に要するクロック数と関数呼び出しクロック数では >後者は無視できるほど小さいっす。 >さらに追加すると標準出力へ出力する際の実処理のクロック数のほうがもっと多い。 >ボトルネックでないところのクロック数を頑張って減らしても全体の速度は大差ない。 で、vfprintf()を使ったdebug_write()にて、フラグか何かを参照し、 デバッグモードでないときは即座にreturnするようにしたとしても、 関数呼び出しそのもののオーバーヘッドは消せない、というのが趣旨なので、 「関数呼び出しのオーバーヘッド」と、「文字化や出力のオーバーヘッド」を 比べているわけではありません。 ただまあ、そのうえで、関数呼び出しのボトルネックだって無視できるほど小さい、 というのは、まあそうだろうなとは思います。ことがデバッグライトだけに、 「本番では死ぬほどループする処理に、1行おきにデバッグライトを入れた」という 状況はもちろん考えられますが。
[この投稿を含むスレッドを表示] [この投稿を削除]