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)。うーん、やだなぁ。