Tchar.h generic-text mapping cheatsheet を作るときに問題となったのが、 「C言語の #define 展開を沢山一気に確認するにはどうすればよいか?」 ということである。

もっとも一個一個ならばIDE上でマウスホーバーすれば展開表示されるので このようなことを思う必要はない。

VC上での #define 展開表示

そこでコンパイラによって実際に展開させることにした。 コンパイラのプリプロセッサ展開だけをさせることも考えたが、 出力の整形も一気にやらせることを考えたので 普通にC言語のプログラムを書くことにした。

このとき一つ注意が必要だったので、備忘録としてメモっておく。

#define FOO bar

printf("%s", FOO);

これはコンパイラによって下記のように展開される(C言語として妥当ではないのでプリプロセッサ処理まででコンパイルエラーになる)

printf("%s", bar);

今したいのはこの展開後を「テキスト」として取得したいので ここでマクロの # を使うことにした。

#define STRINGIFY(x) (#x)
#define FOO bar

printf("%s", STRINGIFY(FOO));

しかし実はこれは予期する動作にならず、 下記のようになる:

printf("%s", ("FOO"));

展開させつつ、テキストに変換するにはマクロを二重にする必要があるらしい。

#define STRINGIFY_(x) (#x)
#define STRINGIFY(x) (STRINGIFY_(x))
#define FOO bar

printf("%s", STRINGIFY(FOO));

これで望んだ展開がやっと得られる。

printf("%s", (("bar")));

逆に言えば、 # を含むマクロを間接的に呼んだ場合、 実際に書かれたものと違って展開されてしまうので 注意が必要ということになる。

#define STRINGIFY0(x) (#x)
#define STRINGIFY1(x) (STRINGIFY0(x))
#define STRINGIFY2(x) (STRINGIFY1(x))
#define FOO BAR
#define BAR baz

printf("%s", STRINGIFY0(FOO));
printf("%s", STRINGIFY1(FOO));
printf("%s", STRINGIFY2(FOO));
printf("%s", STRINGIFY0(BAR));
printf("%s", STRINGIFY1(BAR));
printf("%s", STRINGIFY2(BAR));

printf("%s", ("FOO"));
printf("%s", (("baz")));
printf("%s", ((("baz"))));
printf("%s", ("BAR"));
printf("%s", (("baz")));
printf("%s", ((("baz"))));