#define ディレクティブ
プリプロセッサー定義ディレクティブ は、これ以降のマクロ の出現を、指定された置換トークンに置き換えるようプリプロセッサーに指示 します。
- const オブジェクトは変数のスコープ規則に従いますが、 #define を使用して作成される定数はそうではありません。
- const オブジェクトと違って、マクロはインラインで展開されるので、マクロの値は、コンパイラーが使用する中間表現には含まれません。 インライン展開をすると、デバッガーはマクロ値を使用できなくなります。
- マクロは、ビット・フィールド長などのコンパイル時定数式の中で使用できますが、const オブジェクトは使用できません。
オブジェクト類似マクロ
#define COUNT 1000
int arry[COUNT];
int arry[1000];
#define MAX_COUNT COUNT + 100
プリプロセッサーは、MAX_COUNT のこれ以降の出現を COUNT + 100 で置き換えます。 次に、プリプロセッサーは、これを 1000 + 100 で置き換えます。
#define a 10
doubl d = a.2
関数類似マクロ
関数類似マクロは、オブジェクト類似マクロより複雑であって、その定義は、 仮パラメーターの名前をコンマで区切って、括弧で囲んで宣言します。 空の正式パラメーター・リストは有効です。そのようなマクロを使用して、引数を取らない関数をシミュレートすることができます。 C99 は、可変個の引数を持つ関数類似マクロのサポートを追加しました。
- 関数類似マクロの定義
- 小括弧に囲まれたパラメーター・リストおよび置換トークンが後ろに続く ID。
パラメーターを置換コード内に組み込みます。
空白文字で、ID (マクロの名前) とパラメーター・リストの左括弧とを分離することはできません。
コンマで各パラメーターを区切る必要があります。
移植性のため、1 つのマクロに は、パラメーターが 31 を超えないようにする必要があります。パラメーター・リストは、仮パラメーターとして、省略符号 (…) で終了することができます。 この場合には、置換リストに ID __VA_ARGS__ を使用できます。
- 関数類似マクロの呼び出し
- 小括弧に入れられた、コンマで区切られた引数のリストが後に続く ID。
引数の数は、マクロ定義内のパラメーター・リストが省略符号で終了
するのでなければ、定義内のパラメーターの数と一致しなければなりません。
定義内のパラメーター・リストが省略符号で終了する場合、マクロ呼び出しでの引数の数は、定義内のパラメーターの数に一致するかそれを超えるはずです。
この超過部分は、後続引数 と呼ばれます。
プリプロセッサーは、関数類似マクロの呼び出しを確認すると、引数の置換を行います。
置換コード内のパラメーターは、対応する引数に置き換えられます。
マクロ定義で後続引数が許可されている場合、その引数は
間にコンマが挿入されて、その引数全体が単一の引数であるかのように、
ID __VA_ARGS__ を置き換えます。
引数自体に含まれるマクロの呼び出しはすべて、
引数が置換コード内の対応するパラメーターと置き換わる前に、完全に置き換えられます。マクロ引数は空でもかまいません (ゼロ個のプリプロセス・トークンで 構成されます)。 次に例を示します。
#define SUM(a,b,c) a + b + c SUM(1,,3) /* No error message. 1 is substituted for a, 3 is substituted for c. */
#define debug(...) fprintf(stderr, __VA_ARGS__)
debug("flag"); /* Becomes fprintf(stderr, "flag"); */
- 文字定数内にある。
- ストリング・リテラル内にある。
- 小括弧で囲まれている。
#define SUM(a,b) (a + b)
c = SUM(x,y);
c = d * SUM(x,y);
c = (x + y);
c = d * (x + y);
#define SQR(c) ((c) * (c))
y = SQR(a + b);
y = ((a + b) * (a + b));
y = (a + b * a + b);
# 演算子および ## 演算子の引数は、 関数類似マクロのパラメーターの置換の前に 変換されます。
プリプロセッサー ID は、いったん定義されると、言語のスコープ規則に関係なく、定義されたままとなります。 マクロ定義のスコープは定義から始まり、 対応する #undef ディレクティブに遭遇するまで終了しません。対応する #undef ディレクティブがない場合、そのマクロ定義 のスコープは、変換単位の終わりまで続きます。
#define x(a,b) x(a+1,b+1) + 4
x(20,10)
x(20+1,10+1) + 4
マクロ x を、それ自体の中で繰り返し展開しようとするよりも、 上述の展開を行います。 マクロ x が展開された後で、そのマクロは、関数 x() の呼び出しとなります。
#define debug
2 番目のプリプロセッサー #define ディレクティブを用いて、 定義済みの ID またはマクロの定義を変更することができます。 ただし、2 番目のプリプロセッサー #define ディレクティブの前に、 プリプロセッサー #undef ディレクティブがある場合に限ります。#undef ディレクティブは、最初の定義を無効にして、 同じ ID を再定義で使用できるようにします。
プログラムのテキスト内で、プリプロセッサーは、マクロ定義、マクロの未定義化、またはマクロ呼び出しについて、コメント、文字定数、またはストリング定数をスキャンすることはありません。
以下のプログラム例には、2 つのマクロ定義と、その定義されている両方のマクロを 参照するマクロ呼び出しが含まれています。
/**This example illustrates #define directives.**/
void printf(const char*, ...);
#define SQR(s) ((s) * (s))
#define PRNT(a,b) ¥
printf("value 1 = %d¥n", a); ¥
printf("value 2 = %d¥n", b)
int main(void)
{
int x = 2;
int y = 3;
PRNT(SQR(x),y);
return(0);
}
プリプロセスされた後、このプログラムは、以下と等価のコードによって置き換えられます。
void printf(const char*, ...);
int main(void)
{
int x = 2;
int y = 3;
printf("value 1 = %d¥n", ( (x) * (x) ) );
printf("value 2 = %d¥n", y);
return(0);
}
value 1 = 4
value 2 = 3

可変数引数マクロ (variadic macro) 拡張機能は、可変数の引数を持つマクロに関連した、C99 の 2 つの拡張機能です。これらの拡張の 1 つは、変数引数 ID を __VA_ARGS__ からユーザー定義の ID に名前変更するためのメカニズムです。 もう 1 つの拡張機能は、変数引数が指定されていない場合に、可変数引数マクロ内のダングリング・コンマを除去するための手段を提供します。 どちらの拡張機能も、GNU C を使用して開発された プログラムの移植を容易にするためにインプリメントされています。
#define debug1(format, ...) printf(format, ## __VA_ARGS__)
#define debug2(format, args ...) printf(format, ## args)
| 呼び出し | マクロ展開の結果 |
|---|---|
| debug1("Hello %s/n", "World"); | printf("Hello %s/n", "World"); |
| debug2("Hello %s/n", "World"); | printf("Hello %s/n", "World"); |
プリプロセッサーは、関数マクロへの変数引数が省略されるかまたは空であり、関数マクロ定義内の変数引数 ID の前に ## を伴うコンマがある場合に、末尾のコンマを除去します。
