名前空間
変種
操作

テキストマクロの置換

From cppreference.com

プリプロセッサは、テキストマクロの置換と関数形式のテキストマクロの置換をサポートしています。

目次

[編集] 構文

#define 識別子 置換リスト (オプション) (1)
#define 識別子 ( パラメータ ) 置換リスト (2)
#define 識別子 ( パラメータ, ... ) 置換リスト (3) (C99以降)
#define 識別子 ( ... ) 置換リスト (4) (C99以降)
#undef 識別子 (5)

[編集] 説明

[編集] #define ディレクティブ

#define ディレクティブは、識別子をマクロとして定義します。つまり、コンパイラに識別子のそれ以降のすべての出現を、オプションでさらに処理できる置換リストに置き換えるように指示します。識別子がすでに何らかのマクロとして定義されている場合、定義が同一でない限りプログラムは不正な形式となります。

[編集] オブジェクト形式マクロ

オブジェクト形式マクロは、定義された識別子のすべての出現を置換リストに置き換えます。#define ディレクティブのバージョン(1)はこのように機能します。

[編集] 関数形式マクロ

関数形式マクロは、定義された識別子の各出現を置換リストに置き換えます。さらに、いくつかの引数を取り、それらは置換リスト内の対応するパラメータの出現に置き換えられます。

関数形式マクロ呼び出しの構文は、関数呼び出しの構文と似ています。マクロ名に続く `(` の各インスタンスが、プリプロセッシングトークンのシーケンスの先頭となり、そのシーケンスは置換リストによって置き換えられます。シーケンスは、一致する `)` トークンによって終了され、その間にある左括弧と右括弧のペアはスキップされます。

引数の数は、マクロ定義の引数(パラメータ)の数と同じでなければなりません。それ以外の場合、プログラムは不正な形式となります。識別子が関数表記(つまり、後に括弧がない)でない場合、それはまったく置換されません。

#define ディレクティブのバージョン(2)は、単純な関数形式マクロを定義します。

#define ディレクティブのバージョン(3)は、可変個の引数を持つ関数形式マクロを定義します。追加の引数は `__VA_ARGS__` 識別子を使用してアクセスでき、これは指定された識別子に置き換えられます。

#define ディレクティブのバージョン(4)は、可変個の引数を持つ関数形式マクロを定義しますが、通常の引数は持ちません。引数は `__VA_ARGS__` 識別子のみでアクセスでき、これは指定された識別子に置き換えられます。

バージョン(3,4)では、置換リストに `__VA_OPT__(` 内容 `)` トークンシーケンスを含めることができ、これは `__VA_ARGS__` が空でない場合に内容に置き換えられ、そうでなければ何も展開されません。

#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
F(a, b, c) // replaced by f(0, a, b, c)
F()        // replaced by f(0)
 
#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)
G(a, b, c) // replaced by f(0, a, b, c)
G(a, )     // replaced by f(0, a)
G(a)       // replaced by f(0, a)
 
#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
SDEF(foo);       // replaced by S foo;
SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 };
(C23以降)


注: 関数形式マクロの引数に、一致する括弧のペアで保護されていないカンマが含まれている場合(例: macro(array[x = y, x + 1]) または atomic_store (p, (struct S){ a, b });)、そのカンマはマクロ引数の区切り文字として解釈され、引数の数の一致エラーによりコンパイルが失敗します。

[編集] # および ## 演算子

関数形式マクロでは、置換リスト内の識別子の前に `#` 演算子を付けると、その識別子はパラメータ置換を経て、結果が引用符で囲まれ、文字列リテラルが効果的に作成されます。さらに、プリプロセッサは、引用符で囲まれた埋め込み文字列リテラルがある場合、それらをエスケープするためにバックスラッシュを追加し、必要に応じて文字列内のバックスラッシュを二重にします。すべての先頭と末尾の空白は削除され、テキストの中間(埋め込み文字列リテラルの内部を除く)の空白のシーケンスは単一のスペースに折りたたまれます。この操作は「文字列化」と呼ばれます。文字列化の結果が有効な文字列リテラルでない場合、動作は未定義です。

`#` が `__VA_ARGS__` の前に現れる場合、展開された `__VA_ARGS__` 全体が引用符で囲まれます。

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int")
(C99以降)

`##` 演算子は、置換リスト内の隣接する2つの識別子の間に置かれると、それらの識別子に対してパラメータ置換を実行し、結果を連結します。この操作は「連結」または「トークンペースト」と呼ばれます。有効なトークンを形成するトークンのみをペーストできます。つまり、より長い識別子を形成する識別子、数値を形成する数字、または `+=` を形成する `+` と `=` 演算子です。コメントは `/` と `*` をペーストして作成することはできません。これは、マクロ置換が考慮される前にコメントがテキストから削除されるためです。連結の結果が有効なトークンでない場合、動作は未定義です。

注: 一部のコンパイラは、`##` をカンマの後に `__VA_ARGS__` の前に置くことを許可する拡張機能を提供しています。この場合、`##` は `__VA_ARGS__` が空でない場合は何もせず、`__VA_ARGS__` が空の場合はカンマを削除します。これにより、fprintf (stderr, format, ##__VA_ARGS__) のようなマクロを定義できます。

`#` および `##` 演算子の評価順序は未指定です。

[編集] #undef ディレクティブ

#undef ディレクティブは、識別子の定義を解除します。つまり、`#define` ディレクティブによる識別子の以前の定義を取り消します。識別子に関連付けられたマクロがない場合、ディレクティブは無視されます。

[編集] 事前定義マクロ

以下のマクロ名は、すべての翻訳単位で事前定義されています。

__STDC__
整数定数 1 に展開されます。このマクロは、準拠した実装を示すためのものです。
(マクロ定数)
__STDC_VERSION__
(C95)
C標準のバージョンごとに値が増加する、long 型の整数定数に展開されます。
  • 199409L (C95)
  • 199901L (C99)
  • 201112L (C11)
  • 201710L (C17)
  • 202311L (C23)
    (マクロ定数)
__STDC_HOSTED__
(C99)
実装がホストされている(OS上で実行される)場合は整数定数 1 に、フリースタンディング(OSなしで実行される)の場合は 0 に展開されます。
(マクロ定数)
__FILE__
現在のファイル名を文字列リテラルとして展開します。`#line` ディレクティブによって変更される可能性があります。
(マクロ定数)
__LINE__
ソースファイル行番号を整数定数として展開します。`#line` ディレクティブによって変更される可能性があります。
(マクロ定数)
__DATE__
翻訳の日付を、"Mmm dd yyyy" の形式の文字列リテラルとして展開します。月名は `asctime` によって生成されたものと同様であり、"dd" の最初の文字は、日数が10未満の場合にはスペースになります。
(マクロ定数)
__TIME__
`asctime()` によって生成された時間と同様に、"hh:mm:ss" の形式の文字列リテラルとして翻訳時刻を展開します。
(マクロ定数)
__STDC_UTF_16__
(C23)
`char16_t` がUTF-16エンコーディングを使用することを示すために、1 に展開されます。
(マクロ定数)
__STDC_UTF_32__
(C23)
`char32_t` がUTF-32エンコーディングを使用することを示すために、1 に展開されます。
(マクロ定数)
__STDC_EMBED_NOT_FOUND____STDC_EMBED_FOUND____STDC_EMBED_EMPTY__
(C23)
それぞれ 012 に展開されます。
(マクロ定数)

以下の追加のマクロ名は、実装によって事前定義される場合があります。

__STDC_ISO_10646__
(C99)
`wchar_t` がUnicodeを使用する場合、`yyyymmL` の形式の整数定数に展開されます。日付は、サポートされているUnicodeの最新リビジョンを示します。
(マクロ定数)
__STDC_IEC_559__
(C99)
IEC 60559 がサポートされている場合、1 に展開されます((非推奨)(C23以降))。
(マクロ定数)
__STDC_IEC_559_COMPLEX__
(C99)
IEC 60559 複素数算術がサポートされている場合、1 に展開されます((非推奨)(C23以降))。
(マクロ定数)
__STDC_UTF_16__
(C11)
`char16_t` がUTF-16エンコーディングを使用する場合、1 に展開されます。
(マクロ定数)
__STDC_UTF_32__
(C11)
`char32_t` がUTF-32エンコーディングを使用する場合、1 に展開されます。
(マクロ定数)
__STDC_MB_MIGHT_NEQ_WC__
(C99)
基本文字セットのメンバーに対して `L'x' == 'x'` が偽になる可能性がある場合(例: `wchar_t` にUnicodeを使用するEBCDICベースのシステム)、1 に展開されます。
(マクロ定数)
__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)
自動記憶域期間の可変長配列(およびC23以降では可変修飾型)がサポートされていない場合、1 に展開されます(および可変修飾型(C23まで)自動記憶域期間の(C23以降))。
(マクロ定数)
__STDC_IEC_60559_BFP__
(C23)
IEC 60559 バイナリ浮動小数点演算がサポートされている場合、202311L に展開されます。
(マクロ定数)
__STDC_IEC_60559_DFP__
(C23)
IEC 60559 10進浮動小数点演算がサポートされている場合、202311L に展開されます。
(マクロ定数)
__STDC_IEC_60559_COMPLEX__
(C23)
IEC 60559 複素数算術がサポートされている場合、202311L に展開されます。
(マクロ定数)
__STDC_IEC_60559_TYPES__
(C23)
IEC 60559 交換型および拡張型がサポートされている場合、202311L に展開されます。
(マクロ定数)

これらのマクロの値(`__FILE__` と `__LINE__` を除く)は、翻訳単位全体で一定です。これらのマクロを再定義または未定義しようとすると、未定義の動作が発生します。

事前定義変数 `__func__`(詳細は関数定義を参照)は、プリプロセッサマクロではありません。ただし、`assert` などで `__FILE__` および `__LINE__` と一緒に使用されることがあります。

(C99以降)

[編集]

#include <stdio.h>
 
// make function factory and use it
#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(billion);               // note the lack of quotes
}

出力

quadruple(13): 52
double(21): 42
34
billion

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に発行されたC規格に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
DR 321 C99 `L'x' == 'x'` が常に成り立つかどうか不明確でした。
基本文字セットの間で。
この目的のために `__STDC_MB_MIGHT_NEQ_WC__` が追加されました。

[編集] 参照

  • C23標準 (ISO/IEC 9899:2024)
  • 6.10.4 マクロ置換 (p: 187-184)
  • 6.10.9 事前定義マクロ名 (p: 186-188)
  • C17標準 (ISO/IEC 9899:2018)
  • 6.10.3 マクロ置換 (p: 121-126)
  • 6.10.8 事前定義マクロ名 (p: 127-129)
  • C11標準 (ISO/IEC 9899:2011)
  • 6.10.3 マクロ置換 (p: 166-173)
  • 6.10.8 事前定義マクロ名 (p: 175-176)
  • C99標準 (ISO/IEC 9899:1999)
  • 6.10.3 マクロ置換 (p: 151-158)
  • 6.10.8 事前定義マクロ名 (p: 160-161)
  • C89/C90標準 (ISO/IEC 9899:1990)
  • 3.8.3 マクロ置換
  • 3.8.8 事前定義マクロ名

[編集] 関連項目

C++ドキュメント 「テキストマクロの置換」について
English 日本語 中文(简体) 中文(繁體)