テキストマクロの置換
プリプロセッサはテキストマクロの置換および関数ライクなテキストマクロの置換をサポートします。
目次 |
[編集]構文
#define identifierreplacement-list(オプション) | (1) | ||||||||
#define identifier( parameters) replacement-list | (2) | ||||||||
#define identifier( parameters, ... ) replacement-list | (3) | (C99以上) | |||||||
#define identifier( ... ) replacement-list | (4) | (C99以上) | |||||||
#undef identifier | (5) | ||||||||
[編集]説明
[編集]#define
指令
#define
指令は identifier をマクロとして定義します。 これは、すべての一連の identifier の出現を replacement-list に置き換えるようコンパイラに指示します。 オプションでさらに処理されることもあります。 識別子がすでに何らかの種類のマクロとして定義されている場合、その定義が同一でなければ、プログラムは ill-formed です。
[編集]オブジェクトライクなマクロ
オブジェクトライクなマクロは定義された identifier のすべての出現を replacement-list で置き換えます。 #define
指令のバージョン (1) はまさにそのように動作します。
[編集]関数ライクなマクロ
関数ライクなマクロは、定義された identifier のそれぞれの出現を replacement-list で置き換え、さらに任意個の引数を取り、 replacement-list 内の対応するあらゆる parameters の出現を置き換えます。
関数ライクなマクロの呼び出しの構文は関数呼び出しの構文に似ています。 次のプリプロセッサトークンとして ( が続くマクロ名のそれぞれの実体は、 replacement-list によって置き換えられるトークンの並びを導入します。 この並びは対応する ) トークンによって終了します (間に入る開き括弧と閉じ括弧の対応する組はスキップされます)。
引数の数はマクロ定義内の引数 (parameters) の数と同じでなければならず、そうでなければプログラムは ill-formed です。 識別子が関数表記でない、すなわち、後に括弧が続かない場合は、一切置換されません。
#define
指令のバージョン (2) は単純な関数ライクなマクロを定義します。
#define
指令のバージョン (3) は可変長引数を持つ関数ライクなマクロを定義します。 追加の引数は置換される識別子と共に供給される識別子 __VA_ARGS__
を用いてアクセスできます。 __VA_ARGS__
は引数で置換されます。
#define
指令のバージョン (4) は可変長引数を持つけれども正規の引数を持たない関数ライクなマクロを定義します。 引数は置換される識別子と共に供給される __VA_ARGS__
識別子を用いてのみアクセスできます。 __VA_ARGS__
は引数で置換されます。
ノート: 関数ライクなマクロの引数に、対応する開き括弧と閉じ括弧の組で保護されていないコンマが含まれている場合 (macro(array[x = y, x +1]) や atomic_store(p, (struct S){ a, b }); など)、そのコンマはマクロ引数の区切りもじとして解釈されます。 これは実引数の数の不一致によるコンパイルの失敗を発生させます。
[編集]#
および ##
演算子
関数ライクなマクロにおいて、 replacement-list 内の識別子の前の #
演算子は、その識別子の引数置換を処理した後、その結果を引用符で囲みます (実質的に文字列リテラルを作成します)。 さらに、プリプロセッサは必要に応じて、埋め込まれる文字列リテラル (もしあれば) の周りの引用符をエスケープするためにバックスラッシュを追加し、文字列内のバックスラッシュを二重化します。 すべての先行および後続するホワイトスペースは除去され、テキストの途中 (埋め込まれた文字列リテラルの内部は除く) のホワイトスペースのあらゆる並びは単一のスペースに圧縮されます。 この操作は「文字列化」と言います。 文字列化の結果が有効な文字列リテラルでない場合、動作は未定義です。
#define showlist(...) puts(#__VA_ARGS__) showlist();// puts("") に展開されます。 showlist(1, "x", int);// puts("1, \"x\", int") に展開されます。 | (C99以上) |
replacement-list 内の任意の2つの連続する識別子の間の ##
演算子は、その2つの識別子の引数置換を処理した後、その結果を連結します。 この操作は「連結」または「トークンの貼り合わせ」と言います。 合わせて有効なトークンを形成するトークンのみが連結できます。 より長い識別子を形成する識別子、数値を形成する数字、 +=
を形成する +
と =
などです。 コメントはマクロ置換が考慮される前にテキストから除去されるため、 /
と *
を連結してコメントを作ることはできません。 連結の結果が有効なトークンでない場合、動作は未定義です。
ノート: コンパイラによってはコンマの後 __VA_ARGS__ の前に ## が現れることを許容する拡張を提供します。 この場合 ## は __VA_ARGS__ が空でないときは何もしませんが、 __VA_ARGS__ が空のときはコンマを除去します。 これは fprintf (stderr, format, ##__VA_ARGS__)
のようなマクロを定義することを可能とします。
# および ## 演算子の評価順序は未規定です。
[編集]#undef
指令
#undef
指令は identifier の定義を削除します。 つまり、 #define
指令による identifier の以前の定義を取り消します。 その識別子に紐付くマクロがない場合、その指令は無視されます。
[編集]定義済みのマクロ
以下のマクロはすべての翻訳単位であらかじめ定義されています。
__STDC__ | 整数定数 1 に展開されます。 このマクロは準拠した処理系であることを示すことが意図されています。 (マクロ定数) |
__STDC_VERSION__ (C95) | C 標準のバージョンごとに増加する値を持つ long 型の整数定数に展開されます。
|
__STDC_HOSTED__ (C99) | 処理系がホスト環境 (OS の下で実行される) の場合は整数定数 1、フリースタンディング環境 (OS なしで実行される) の場合は 0 に展開されます。 (マクロ定数) |
__FILE__ | 文字列リテラルとしての現在のファイルの名前に展開されます。 #line 指令で変更できます。 (マクロ定数) |
__LINE__ | ソースファイルの行番号 (整数定数) に展開されます。 #line 指令で変更できます。 (マクロ定数) |
__DATE__ | 翻訳の日付 ("Mmm dd yyyy" 形式の文字列リテラル) に展開されます。 月の名前は asctime によって生成されたかのようになり、 dd の1文字目は日が10未満の場合は空白になります。 (マクロ定数) |
__TIME__ | 翻訳の時刻 ("hh:mm:ss" 形式の文字列リテラル) に展開されます。 asctime() によって生成された時刻であるかのようになります。 (マクロ定数) |
処理系によっては以下の追加のマクロ名があらかじめ定義されていることがあります。
__STDC_ISO_10646__ (C99) | wchar_t が Unicode を使用する場合は yyyymmL 形式の整数定数に展開されます。 この数値はサポートされている Unicode の最新のリビジョンを表す日付です。 (マクロ定数) |
__STDC_IEC_559__ (C99) | IEC 60559 がサポートされている場合は 1 に展開されます。 (マクロ定数) |
__STDC_IEC_559_COMPLEX__ (C99) | IEC 60559 の複素数算術がサポートされている場合は 1 に展開されます。 (マクロ定数) |
__STDC_UTF_16__ (C11) | char16_t が UTF-16 エンコーディングを使用する場合は 1 に展開されます。 (マクロ定数) |
__STDC_UTF_32__ (C11) | char32_t が UTF-32 エンコーディングを使用する場合は 1 に展開されます。 (マクロ定数) |
__STDC_MB_MIGHT_NEQ_WC__ (C99) | 基本文字集合のメンバ x について 'x'== L'x' が偽と成り得る場合は 1 に展開されます。 wchar_t に Unicode を使用する EBCDIC ベースのシステムなどが該当します。 (マクロ定数) |
__STDC_ANALYZABLE__ (C11) | 解析可能性がサポートされる場合は 1 に展開されます。 (マクロ定数) |
__STDC_LIB_EXT1__ (C11) | 境界チェックインタフェースがサポートされる場合は整数定数 201112L に展開されます。 (マクロ定数) |
__STDC_NO_ATOMICS__ (C11) | アトミック型およびアトミック操作ライブラリがサポートされない場合は 1 に展開されます。 (マクロ定数) |
__STDC_NO_COMPLEX__ (C11) | 複素数型および複素数学ライブラリがサポートされない場合は 1 に展開されます。 (マクロ定数) |
__STDC_NO_THREADS__ (C11) | マルチスレッドがサポートされない場合は 1 に展開されます。 (マクロ定数) |
__STDC_NO_VLA__ (C11) | 可変長配列がサポートされない場合は 1 に展開されます。 (マクロ定数) |
これらのマクロ (__FILE__
と __LINE__
は除く) の値は翻訳単位を通して一定です。 これらのマクロを再定義または削除する試みは未定義動作です。
定義済みの変数 __func__ (詳細は関数定義を参照してください) は、 assert などで | (C99以上) |
[編集]例
#include <stdio.h> // 関数のファクトリを作成し、それを使用します。#define FUNCTION(name, a) int fun_##name(int x) { return (a)*x;} FUNCTION(quadruple, 4) FUNCTION(double, 2) #undef FUNCTION#define FUNCTION 34#define OUTPUT(a) puts( #a ) int main(void){printf("quadruple(13): %d\n", fun_quadruple(13));printf("double(21): %d\n", fun_double(21));printf("%d\n", FUNCTION); OUTPUT(million);// 引用符がないことに注意してください。}
出力:
quadruple(13): 52 double(21): 42 34 million
[編集]参考文献
- C11 standard (ISO/IEC 9899:2011):
- 6.10.3 Macro replacement (p: 166-173)
- 6.10.8 Predefined macro names (p: 175-176)