プリプロセッサマクロを文字列に変換する - C++ プログラミング

PROGRAM


プリプロセッサマクロを文字列に変換する

テストプログラムを書いているときなど、同じ処理をさまざまな値で実行して、その結果を画面に表示したい場合があります。

たとえば、16 進数表記の数値をいろいろな型にキャストして、その値がどうなったかを表示してみたいとします。

std::cout << "(signed char)0xE7 は " << (int)(signed char)0xE7 << "です。" << std::endl;

そこでこのようにして、(signed char) にキャストした 0xE7 の値がどうなるかを、次の表示形式で見られるようにしてみました。

(signed char)0xE7 は -25 です。

 

これをさまざまな値と型でテストしたい場合、毎回 std::cout とかを記載するのは面倒ですし、追加で別の情報も表示したくなったら、全ての行を調整しないと行けなくなります。

そんなとき C++ では、#define でマクロを定義して、テストしたい値を引数に渡すのが一般的と思いますけど、そのとき、どのような値をテストしたかを画面に表示できると、たくさんのテストをしたときに結果が判りやすくて便利です。

 

マクロの引数に渡した式をそのまま文字列化する

マクロでは、引数名の先頭に # をつけることで、その引数の内容を丸ごと文字列として扱ってくれる機能があります。

それを使って今回は、次のようにしてマクロを定義してみます。

#define test(value) std::cout << #value " は " << (int)(value) << "です。" << std::endl

こうすることで、#value は value に指定した式をそのまま文字列に変換したものに置き換えられます。マクロでは続く文字列はそのまま連結されるので、これでテスト項目を表示する部分がマクロで定義できました。

その後に出てくる value は # を付けていないので、与えられた式がそのままここに埋め込まれます。

 

これで、次のようにしてテストを実行することができるようになりました。

test((signed char)0xE7);

表示される結果は、マクロにする前と同じです。

このようにすれば、複数のパターンでテストを行いたいときも簡単ですね。

test((signed char)0xE7);

test((unsigned char)0xE7);

test((char)0xE7);

test((signed char)0xFF);

test((signed char)0xC0);

 

引数に渡したマクロを展開して文字列化したい場合

なお、# を付けて文字列化する場合、そこに別のマクロ名を指定しても、指定したまんまが文字列として採用されます。

そのため、例えばテスト項目も "#define (signed char)0xE7 pattern1" というように定義していた場合、これを先ほどの test マクロに渡しても、# を付けて文字列化している部分では、渡したまんまの "pattern1" として扱われてしまいます。

# を付けないところでは、普段通り展開されます。

#define (signed char)0xE7 pattern1

 

test(pattern1);

つまりこのようにすると、次のような結果表示になってしまいます。

pattern1 は -25 です。

 

こういうときにも展開後の式を表示させたいときには、展開されるようにワンクッション置く必要があります。

#define testWithTitle(title, value) std::cout << #title " は " << (int)(value) << "です。" << std::endl

#define test(value) testWithTitle(value, value)

こうしてあげると、test マクロの value として指定した式が、testWithTest マクロを呼び出すときに展開されて、title と value のそれぞれの引数として渡されます。

呼び出された testWithTitle マクロでは、引数には既に展開済みの式が渡ってくるので、#title では、展開された式を文字列化することができることになります。


[ もどる ]