
C言語入門|条件付きコンパイルのしくみ
― ソースコードを状況に応じて切り替える技術
「#define は危ないし、もう使わなくてもいいんじゃない?」
そんな気持ちになるのも無理はありません。
ですが、プリプロセッサには
今でも現役で役立つ機能 がもう1つあります。
それが 条件付きコンパイル です。
条件付きコンパイルを使うと、
同じソースコードから、用途の異なる実行ファイルを作る
ことができます。

条件付きコンパイルとは何か
条件付きコンパイルとは、
コンパイル前の段階で、ソースコードの一部を有効・無効に切り替える仕組み
のことです。
重要なのは、これは if 文のような
実行時の分岐ではない
という点です。
- if 文:プログラム実行中に条件判定
- 条件付きコンパイル:コンパイル前にコード自体を削除・残存させる
つまり、不要なコードは 最初から実行ファイルに含まれません。
条件付きコンパイルの基本例
次の例を見てみましょう。
#include <stdio.h>
#define BUILD_MODE 3
int main(void)
{
int level = 0;
#ifdef BUILD_MODE
printf("BUILD MODE is enabled\n");
#endif
#ifndef BUILD_MODE
printf("RELEASE MODE is enabled\n");
#endif
#if (BUILD_MODE == 1)
level = 1;
#elif (BUILD_MODE == 2)
level = 2;
#elif (BUILD_MODE == 3)
level = 3;
#else
level = 9;
#endif
printf("level=%d\n", level);
return 0;
}実行結果
BUILD MODE is enabled
level=3この結果は、BUILD_MODE が定義され、かつ 3 に設定されている
という条件をプリプロセッサが事前に評価した結果です。
プリプロセッサによる分岐の流れ(図のイメージ)

図の説明
この図では、
- ソースコードがプリプロセッサに渡される。
- #define の有無や値を確認
- 条件に合わないコードを削除
- 残ったコードだけをコンパイラへ渡す。
という流れを示しています。
削除されたコードは、コンパイラにすら届かない
という点が、if 文との最大の違いです。
条件付きコンパイルで使う命令
条件付きコンパイルには、次のプリプロセッサ命令を使います。
マクロ定義の有無で判定する
#ifdef マクロ名
#endifマクロが定義されていれば有効になります。
#ifndef マクロ名
#endifマクロが定義されていなければ有効になります。
値や条件式で判定する
#if 条件式
#elif 条件式
#else
#endif条件式には、
数値・関係演算子・論理演算子
を使えます。
ただし、変数は使えません。
あくまで #define された値のみが対象です。
条件付きコンパイルが活躍する場面
条件付きコンパイルは、次のようなケースでよく使われます。
| 利用シーン | 内容 |
|---|---|
| デバッグ | デバッグ時のみログや検査コードを有効にする。 |
| 環境差異 | OS や CPU によって処理を切り替える。 |
| コンパイラ差 | GCC・Clang・Visual C++ でコードを分ける。 |
| 機能制限 | 軽量版・製品版で機能を削減する。 |
特に デバッグコードの切り替え は、
実務でも非常によく登場します。
インデントと可読性の注意点
「あれ? プリプロセッサ命令って、インデントしないの?」
実はこれ、昔からの C 言語文化です。
#ifdef DEBUG
printf("debug\n");
#endifプリプロセッサ命令は
行頭に書くのが慣習
とされています。
ただし、
- 多用しすぎる。
- 入れ子が深くなる。
と、一気に読みにくくなります。
条件付きコンパイルは強力ですが、
使いすぎるとバグの温床になる
ということも覚えておきましょう。
条件付きコンパイルとの上手な付き合い方
条件付きコンパイルは、
- ビルド時にコードを切り替えられる。
- 実行ファイルを軽くできる。
という大きなメリットがあります。
一方で、
- 実行時には確認できない。
- ソースコードが複雑になりやすい。
という弱点もあります。
基本方針
- 必要な場面に限定して使う。
- デバッグ用途に留める。
- 深い入れ子は避ける。
このバランス感覚が、プロのC言語エンジニアには求められます。
