2009年3月18日水曜日

可変長ログの出し方

ユースケース
DEBUG_LOGでprintfと同じような書き方で利用し、ログを出力する。
int main(void)
{
int tryInt = 305419896; // 4 byte
ENTER;
DEBUG_LOG("yao daoding = %d\n", tryInt);

return 0;
}


1. __VA_ARGS__を利用できない場合、C99をサポートしていないコンパイラ
#ifdef D_DEBUG
#define DEBUG_LOG printf("%s %d %s:", __FILE__, __LINE__, __FUNCTION__),printf
#else
#define DEBUG_LOG(...)
#endif
//DEBUG_LOG(...)で記述するところをわざとDEBUG_LOGとして記述するのはミソ

2. 上記は\nを手動で追加しないと、改行を出力してくれないという欠点が
ある。
要は下記記述で、改行を出力することはできない。
DEBUG_LOG("yao daoding = %d", tryInt);
それを防ぐためにはC99がサポートしているという前提だったら、
以下の対策がある。
#ifdef D_DEBUG
#define WGT_TRY_BY_TOU(fmt, ...) printf("%s %d %s "fmt"\n", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
#else
#define DEBUG_LOG(...)
#endif

3. しかし、上記にも欠点があり、引数は一つしかない場合、コンパイルエラーに
なる。
DEBUG_LOG("daoding");
gcc -E main.cで確認すると、下記とおりに展開されているようである。
printf("%s %d %s ""daoding""\n", "main.c", 77, __FUNCTION__, );
余っている,を削除するために、下記方法は考えられる。
#define ENTER WGT_ENTER_LOG2("%s", "Enter", "")
#define WGT_DEBUG_LOG(...) WGT_ENTER_LOG2(__VA_ARGS__, "")

#define WGT_ENTER_LOG2(fmt, ...) \
{ \
printf("%s %d %s ", __FILE__, __LINE__, __FUNCTION__); \
printf(fmt"%s\n", __VA_ARGS__); \
}

すると下記はそれぞれ正常に展開される。
DEBUG_LOG("daoding");
DEBUG_LOG("yao daoding = %d\n", tryInt);
{ printf("%s %d %s ", "main.c", 76, __FUNCTION__); printf("daoding""%s\n", ""); };
{ printf("%s %d %s ", "main.c", 75, __FUNCTION__); printf("yao daoding = %d""%s\n", tryInt, ""); };

4. 運がよければ、下記も利用できるかも
引数は一つしかない場合、##は直前のあまった,を削除してれる。これはC99にはないので、ご注意を
#ifdef D_DEBUG
#define WGT_TRY_BY_TOU(fmt, ...) printf("%s %d %s "fmt"\n", __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__)
#else
#define DEBUG_LOG(...)
#endif

0 件のコメント: