WinXP & VC2003 で開発してます。
デバッグ用にログ情報を収集したいと思います。
そこでログ出力用の関数を作成し、そこに __LINE__ などのマクロを使用して
ソースコードの行番号などを乗せたいと考えました。
たとえば以下のような関数を作成するとします。
debuglog( char* szMessage, int nLine );
これを実際に使用するとパラメータ nLine にこの関数を使用するたびに
__LINE__ を渡す事になりますが、このパラメータへ渡す値はほぼすべて
__LINE__ になるため、省力化?を目的として、省略可能パラメータを
利用できないかと考えました。
debuglog( char* szMessage, int nLine = __LINE__ );
ただこれでは上記の定義が書かれている場所の行番号を取る事になり、
本当に欲しい情報であるこの関数を呼び出した場所の行番号ではなくなってしまいます。
代わりの方法としてマクロを使用して以下のような方法も考えられると思いますが
柔軟さに欠けるように思いました。
#define DEBUGLOG( MSG ) debuglog( MSG, __LINE__ )
このような場合、皆さんならどうしますか。
良い方法があるようでしたらご教示ください。よろしくお願いします。
以上です。
> 柔軟さに欠けるように思いました。
どのような柔軟さが欠けているのですか?
十分テストしてないのでマクロが失敗する可能性もあるし、
もっとうまく書けるような気もするけど、こんなのを書いてみた。
ファイルに出力したい場合、OutputDebugStringを変更してください。
inline void fileline(const TCHAR *file, int line) {
TCHAR buf[1024];
_stprintf(buf, TEXT([my debug]%s(%d) : ), file, line);
OutputDebugString(buf);
}
inline void debuglog(const TCHAR *format, ...)
{
try {
TCHAR buf[4096];
va_list arglist;
va_start(arglist, format);
#ifdef _UNICODE
int ret = _vsnwprintf(buf, sizeof(buf), format, arglist);
#else
int ret = _vsnprintf(buf, sizeof(buf), format, arglist);
#endif
if (ret < 0)
OutputDebugString(TEXT(Buffer OverFlow at debuglog!\n));
else
OutputDebugString(buf);
} catch (...) {
OutputDebugString(TEXT(ERROR at debuglog!\n));
return;
}
}
#define DEBUGLOG fileline(__FILE__, __LINE__), debuglog
// 使用例
{
int x = 5;
char *p = sample;
DEBUGLOG(x : %d, p : %s\n, x, p);
}
struct DebugLog
{
DebugLog(const TCHAR* file, int line) { /*~*/ }
void operator()(const TCHAR* format, ...) { /*~*/ }
};
#define DEBUGLOG DebugLog(__FILE__, __LINE__)
ATLではこんなやり方してますね。
私はこちらのHPで入手できるものを愛用しています。
http://hp.vector.co.jp/authors/VA010766/class/FileTrace.html
なかなか良くできています。
秀丸を使用して、ダイレクトジャンプできるのがなんといっても嬉しいです。
返信をありがとうございます。
お礼が遅くなってしまい、申し訳ありませんでした。
たいちう様
>> 柔軟さに欠けるように思いました。
>どのような柔軟さが欠けているのですか?
最初の案では基本的には関数のパラメータに行番号を指定できます。
が、例示のようなマクロ経由では行番号指定が出来ないため
これを行おうとする場合にはマクロではなく元の関数を直に呼ばねばならず、
同じ関数を呼ぶために複数の名前を使用しなければならなくなる可能性に抵抗が
ありました。
例示をいただいたプログラムについてですが、まさに目から鱗。
発想の転換とはこのことかと思うくらいに感動しました。大げさではなく。
今回想定していた処理ではファイルなどが対象とは限らないため、そのまま
転用することは難しいですが、システムマクロに頼ろうとした部分と
その他のメッセージなどとを処理する関数を別に用意するという発想は
大変に有用と思います。自分では思い付かなかったのが悔しい。
そうですね。
グローバルの変数かなにかに保存させて、それを経由して本体部分の
処理が情報を取得するという風に出来るような気がします。
複数スレッドも考慮して排他も入れる必要があるかな。
ありがとうございました。
kaba様
不勉強なため正直、最初はよく判りませんでしたが(汗、面白いものですね。
興味が出てきました。今回の件とは別に、ATL を勉強をしてみようと思います。
興味深い情報をありがとうございました。
こねこ様
実は私も記録を残すためにログの管理クラスなどを結構自分で書いたりしているのですが
いまさらながらに発見がありました。この発想も貰い、です。
有用な情報をありがとうございました。
以上です。
チェックを忘れていました。