cpp-macro-expand - プリプロセッサのマクロ展開の回数
目的
Cプリプロセッサでのマクロ展開は、再起的に可能か?
結果
不可能。一度展開したマクロは、展開結果にその内容が含まれていても、それ以上展開されない。
(Self-Referential Macros - The C Preprocessorに書かれている通りだった)
以下、詳細。
再帰的に展開されないことの確認
以下のファイルを、プリプロセッサに通してみる。
A; #define A A -> B A; #define B B -> A A; #define X (X is recursive) X;
プリプロセス実行:
% gcc -E -P macro-expand.c | grep . A; A -> B; A -> B -> A; (X is recursive);
"A -> B -> A" の中のAがそれ以上展開されないこと、また、 "(X is recursive)" の X が一度しか展開されていないことから、Cプリプロセッサでのマクロ定義は、1つのシンボルにつき1度しか展開されないことがわかった。
GCCのマニュアル
GCCのプリプロセッサのマニュアルとして、そのものずばりが書かれていた。
`3.10.5 Self-Referential Macros(自己参照マクロ)' (Self-Referential Macros - The C Preprocessor)
A self-referential macro is one whose name appears in its definition. Recall that all macro definitions are rescanned for more macros to replace. If the self-reference were considered a use of the macro, it would produce an infinitely large expansion. To prevent this, the self-reference is not considered a macro call. It is passed into the preprocessor output unchanged.
自己参照マクロとは、自身の名前が定義中にあらわれるマクロのこと。
全てのマクロ定義は、他のマクロ置換えをするために再走査されるので、自己参照の展開は無限ループを起こしてしまう。
この対策として、マクロ定義中の自身の参照はマクロ呼び出しではない、とみなされる。つまり、プリプロセッサは自己参照部分をそのまま出力する。
この他にも、`Macro Pitfalls(マクロの落とし穴)' の項目は読んでおいたほうがよさそう。
- 3.10.1 Misnesting
- マクロ展開の結果もマクロ展開されるので注意
- 3.10.2 Operator Precedence Problems
- マクロ展開結果の優先順位を考慮して、マクロ引数はカッコで括ろう
- 3.10.3 Swallowing the Semicolon
- マクロ定義を複文にする時は、単なる複文({...})にするとif...else の時にelseで構文エラーになるので、do{}while(0)を使おう
- 3.10.4 Duplication of Side Effects
- マクロ引数を複数回評価すると副作用も複数回起きるので、typeofやstatement-expression('({...})')などのGNU拡張を使おう
- 3.10.5 Self-Referential Macros
- 自己参照マクロについて
- 3.10.6 Argument Prescan
- 関数型マクロの引数は、引数展開時とマクロ本体展開時の2回展開されるが('f(f(1))'はfを2回展開したものになるし、文字列化するマクロも同様)、自己参照マクロは例外として1度しか展開されないよ
- 3.10.7 Newlines in Arguments
- 関数型マクロを複数行に渡って使うと、コンパイルエラー時などの行数表示がずれることがあるよ