cpp-macro-expand - プリプロセッサのマクロ展開の回数

目的

Cプリプロセッサでのマクロ展開は、再起的に可能か?

結果

不可能。一度展開したマクロは、展開結果にその内容が含まれていても、それ以上展開されない。
Self-Referential Macros - The C Preprocessorに書かれている通りだった)

以下、詳細。

再帰的に展開されないことの確認

以下のファイルを、プリプロセッサに通してみる。

macro-expand.c
https://sssvn.jp/svn/spikelet/c/cpp-if-parser/spec-check/macro-expand.c
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
関数型マクロを複数行に渡って使うと、コンパイルエラー時などの行数表示がずれることがあるよ