kkamegawaの購入記録

漫画、小説、映画や買ったものの記録をつらつらしていきます。昔は一部技術情報もありました…

C#で__LINE__や__FILE__プリプロセッサマクロを使いたい

画像  ANSI Cではプリプロセッサマクロが用意されています。コンパイルの前処理として実行され、定義済みのトークンをあらかじめ決められた値で置き換えてからコンパイラに渡すという物です。Javaでもそうですが、最近の言語ではプリプロセッサマクロのように、副作用の大きな物は排除しているように見えます。まぁマクロの廃止は誤りの少ないプログラムを書くためには正しいと思うのですが、それでもやはり使いたい物がいくつかあります。  その筆頭が__FILE__と__LINE__。これらはコンパイルの前処理で、「ファイルのフルパス」と「ファイルの行番号」として置き換えられます。特殊定数(INT_MAXとか)のようにプログラムの動作としては役に立ちませんが、タグジャンプ書式のログを吐き出すときは結構便利なのです。私はこんな感じで使っています。 wsprintf(szOutput, "%s(%d) lRet:%ld", __FILE__, __LINE__, lRet); OutputDebugString(szOutput);  これで、VCのデバッグウィンドウにメッセージがずらずらと出ます。私の場合、Platform SDK付属のサンプル、dbmonにちょっと手を入れて、OutputDebugString()の出力をファイルへ出力する改良版を使っています。上記のwsprintf()も実際はフルパスに置き換えられる__FILE__ではなく、絶対パスを除いたファイル名を格納する変数を用意して使っています(お客さんに万一見られたらあれだし)。  さて、C#を使うようになって、最大の不満がプリプロセッサマクロがないこと(というか、__FILE__,__LINE__がないこと)でした。どうやってタグジャンプ付きのログだそうと悩んでいて、ぐぐってみるとやはり世界中で同じ事で悩んでいる人がいます。.NET 247 : hot to write __FILE__ and __LINE__ in C#がまさにそれ。  System.DiagnosticsのStackFrameオブジェクトを使えばよいとのこと。こんな感じ。 using System.Diagnostics; void OutputError(string Message) { StackFrame CallStack = new StackFrame(1, true); string SourceFile = CallStack.GetFileName(), int SourceLine = CallStack.GetFileLineNumber(), MyWriteToFile("Error: " + Message + " - File: " + SourceFile + " Line: " + SourceLine.ToString()); }  ここでStackFrame()のコンストラクタに1を渡しているのは、「一つ前の」スタックを参照するということです。つまり、このOutputError()を呼び出す直前の位置が取得できると。MSDNのヘルプ(2005/02/22現在)にはこう書かれています。
スタック フレームには必ず MethodBase 情報が含まれ、オプションでファイル名、行番号、および列番号の情報も含まれます。 StackFrame 情報は、デバッグ ビルド構成と共に使用すると最も有益な情報となります。既定では、デバッグ ビルドにはデバッグ シンボルが含まれ、リリース ビルドには含まれません。
 それじゃ、リリースでは困るのでは?と思いますが、はたしてその通り。リリースビルドでも、コンパイルオプションで「デバッグ情報の生成:True」(図)にしないとスタックトレース出してくれませんでした(VS .NET2003)。うーん、やだなぁ。