マクロ: 諸刃の剣
テキストの自動置換機能。便利だが、使い方を誤ると地獄を見る。
プリプロセッサ
コンパイルの前に実行されるテキスト処理ツール。#で始まる行を処理する。
マクロ
特定の文字列を別の文字列に置換する機能。
副作用 (Side Effect)
式を評価したとき、値が返るだけでなく状態が変化すること(変数の値が変わるなど)。マクロの引数に副作用を持たせると危険。
詳細解説
コンパイル前の「置換」
コンパイラがコードを読む前に、プリプロセッサというツールが走ります。
#define A B と書くと、プログラム中の A をすべて機械的に B に書き換えます。
これは単なる「コピペ」なので、型のチェックもスコープもありません。便利ですが、現代のC言語(C99以降)では、なるべく const 定数や inline 関数を使うことが推奨されます。
定数と関数マクロ
定数定義
// 定数定義 (古いやり方)#define MAX_USERS 100
// 現代的な推奨// 型があり、デバッガで見えるconst int kMaxUsers = 100;enum { MAX_BUFFER = 1024 };マクロ関数の罠
マクロ関数を使うときは、引数を必ずカッコ <code>((x))</code> で囲む必要があります。さらに、<code>i++</code> のような副作用のある式を渡すと、意図せず複数回実行されてしまう問題があります。
// マクロ関数 (危険!)#define SQUARE(x) ((x) * (x))
int a = 5;int b = SQUARE(a + 1); // ((a + 1) * (a + 1)) -> OK (36)
// 副作用の罠int c = SQUARE(a++);// ((a++) * (a++)) -> aが2回増える!未定義動作!実践テクニック
条件付きコンパイル
<code>#ifdef DEBUG</code> のように書いて、デバッグ時だけログ出力を有効にする使い方は、マクロの正当な(そして非常に便利な)使い道です。
演習課題
課題1: MINマクロ
2つの値の小さい方を返すマクロ MIN(a, b) を定義してください。三項演算子を使うと良いでしょう。
合格ライン
マクロが単なるテキスト置換であることを理解している
マクロ関数に i++ を渡してはいけない理由を知っている