トリッキーなコード その2

このエントリーをはてなブックマークに追加
落ちません落ちません。
とりあえずsage進行で行こう。

昔、VC++でTODOにタグジャンプを付けたいときに、
ものすごくトリッキーなコードを書いた記憶があるな。

コンパイルエラーとかが出ると、VCでは、
C:\project\foo\foo.c(123) error C4001: 何らかのエラー。
C:\project\foo\foo.c(123) warning C4002 : 何らかのワーニング。
という形になるのですが、それと同様に
C:\project\foo\foo.c(123) message : TODOなどのメッセージ
という出力をするマクロを書いた。
これをやると、便利なことにF4でタグジャンプできるので、
TODOメッセージや連絡事項などを忘れることなくソース中に書ける。

完全な処理系依存だとおもうけど、発掘したら公開します。
567.:03/08/30 22:55
>>566
お。便利そうだ。
期待sage (w
検索したら
 ttp://www.microsoft.com/japan/developer/library/vccore/_predir_message.htm
なんてものが一発で見つかったと、検証コードも書かずにカキコしてみるテスト。
569566:03/08/31 02:18
眠れないのでカキコ

>>568
もちろんそれを使うのだが、このプラグマはメッセージを純粋に表示するだけで、
ファイル名や行番号は出してくれないのだ。
で、自分で出力しようと思って、

#define TODO(x) message( __FILE__ "(" __LINE__ ") message: " x )

という定義を書いてみるわけだが(#pragma TODO(...) という使い方を想定)、
__LINE__ が文字列ではなくて数値だということでコンパイルエラーが出る。
そこで、文字列化マクロを使用して

#define _TOSTRING(x) (#x)
#define TODO(x) message( __FILE__ "(" _TOSTRING(__LINE__) ") message: " x )

のように書いてみることを大抵思いつくと思うけど、この出力結果は

C:\project\foo\foo.c(__LINE__) message : メッセージ

となってしまう。__LINE__ が展開されないまま文字列化されてしまうんですよ。
570566:03/08/31 02:24
というわけで、正解はこちら。

#define _TOSTRING(x) (#x)
#define _THRU(x) _TOSTRING(x)
#define TODO(x) message( __FILE__ "(" _THRU(__LINE__) ") message: " x )

間に一つ何もしないマクロをはさむことにより数値展開された上で文字列化されます。
コンパイラのプリプロセッサ内部で構文解析木を作るときに、一度記号表へ入れられるか
直接処理されるか、その内部構造の隙間を利用したトリックですね。
種明かししてしまうと簡単なんだけど、このコードはそこそこ気に入っています。
(ただ手元にソースが無いので、思い出しながら書いているので間違っていたらごめんなさい)
念のため突っ込ませてくれ。Cの仕様で

#error ほげほげ

とか書けるのは知ってるよな? エラーになるので、ワーニングには使えないが。
>>571
コンパイルエラー出したくないから TODO なんだと思うが・・・
>>571
エラーになったらビルドが止まりますから、それはいやですよね。

面白いことに、出力の"message"のところを"error"や"warning"に変えると
なぜかエラーやワーニングのカウントに入れられてしまう罠@VC
良いこと聞いたからage!

たいけど我慢してsage!
>>570
実際に VC でやってみた。
_TOSTRINGマクロは ()でくくるとコンパイルエラーになりまつ。

#define _TOSTRING(x) #x

それから、埋め込むときは

#pragma TODO("さっさと実装しろ。")

のように書く必要あり。
#pragma もマクロに埋め込めるとさらにウマーだが。。。
>>575
サンキュー。やっぱうろ覚えじゃダメだな。

今自分の環境(.NET)でやってみたら、タスク一覧に出てこないから
F4ジャンプなどが出来なくなっている。出力からのタグジャンプは使えるから
使いにくくなったわけじゃないけど、.NETになってしまったら
出力をチェックする人は少ないかもしれないね。

で、相変わらず、自分で#pragma messageを使って出した偽のエラーメッセージに
統合環境は律儀に反応してくれます。
IDEとコンパイラは、標準入出力のみで繋がっているんだね(笑)

>#pragma もマクロに埋め込めるとさらにウマーだが。。。
それ、できるのかなぁ?出来たらかなりトリッキーぽ
ちょっと追記。.NETな人は、

#define TODO(x) message( __FILE__ "(" _THRU(__LINE__) ") : warning : " x )

を使えばタスク一覧にTODOメッセージが出ます(ついでにコンパイラが警告を勘違いして加算します)。
これで.NET環境でも便利に使えるかもしれない

# けど.NETなら標準でこういうツールを用意してそうな気もする。調べてないけど
>#pragma もマクロに埋め込めるとさらにウマーだが。。。
_Pragma…
残念ながらVCじゃ使えないね。
有用なトリックだな。利用させてもらおう。これはいい。
VC++6.0英語版で調べてみたが、↓でも反応するね。

 #define TODO(x) message( __FILE__ "(" _THRU(__LINE__) ") : ToDo : " x )