Jの衝動書き日記

さらりーまんSEの日記でございます。

【C言語】__LINE__を文字列で出力する

__LINE__は、ソース上の行番号を出力するプリプロセッサ・マクロだが、出力される値は数値である。これをログ出力で使いたいのだが、その引数はすべて文字列なので扱えない、なんてことがお仕事であった。
まあ、そのお仕事では時間の関係で諦めてしまったのだが、落ち着いて来たこともあり、__LINE__を文字列として簡単に扱えないかな、と思って調べたら出来るみたいなのでメモ代わりに書いておく。

定義は以下の通り。ヘッダファイル等に書いておけばOK
#define THIS_LINE TOSTR(__LINE__)
#define TOSTR(n) TOSTR_(n)
#define TOSTR_(n) #n

利用法は以下のような感じ
debug_log(__FILE__, THIS_LINE, "hoge");
→ void debug_log(char*,char*,char*)


何故これでOKかというと、たぶん、以下のように展開されるからである。
debug_log(__FILE__, THIS_LINE, "hoge");
↓THIS_LINEの展開
debug_log(__FILE__, TOSTR(__LINE__), "hoge");
↓TOSTRの展開
debug_log(__FILE__, TOSTR_(__LINE__), "hoge");
↓__LINE__の展開
debug_log(__FILE__, TOSTR_(100), "hoge");
↓TOSTR_の展開
debug_log(__FILE__, "100", "hoge")
#マクロ引数名で,引数に渡された変数名・定数名などが展開されずに、そのまま文字列になるらしい。


ちなみに、TOSTR_(n)の定義をなくし、 TOSTR(n) #nとした場合は以下のように展開される。
debug_log(__FILE__, THIS_LINE, "hoge");
↓THIS_LINEの展開
debug_log(__FILE__, TOSTR(__LINE__), "hoge");
↓TOSTRの展開
debug_log(__FILE__, "__LINE__", "hoge");
これは何故かというと、 TOSTR(n)の定義は#nなので、引数nは、展開しないで、そのまま文字列にするためである。故に__LINE__は数値としては展開されず、これがそのまま文字列として展開される。


また、__LINE__は、上記の例ではヘッダファイルにあるが、実際に展開されるソースの行数は、THIS_LINEマクロを配置した場所となる。ヘッダファイルの行数になることはないので心配いらない。


また、マクロの展開状態だけをみたい場合は、gccの-Eオプションで見ることが可能だ。