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 に設定されている
という条件をプリプロセッサが事前に評価した結果です。

プリプロセッサによる分岐の流れ(図のイメージ)

図の説明

この図では、

  1. ソースコードがプリプロセッサに渡される。
  2. #define の有無や値を確認
  3. 条件に合わないコードを削除
  4. 残ったコードだけをコンパイラへ渡す。

という流れを示しています。

削除されたコードは、コンパイラにすら届かない
という点が、if 文との最大の違いです。

条件付きコンパイルで使う命令

条件付きコンパイルには、次のプリプロセッサ命令を使います。

マクロ定義の有無で判定する

#ifdef マクロ名
#endif

マクロが定義されていれば有効になります。

#ifndef マクロ名
#endif

マクロが定義されていなければ有効になります。

値や条件式で判定する

#if 条件式
#elif 条件式
#else
#endif

条件式には、
数値・関係演算子・論理演算子
を使えます。

ただし、変数は使えません
あくまで #define された値のみが対象です。

条件付きコンパイルが活躍する場面

条件付きコンパイルは、次のようなケースでよく使われます。

利用シーン内容
デバッグデバッグ時のみログや検査コードを有効にする。
環境差異OS や CPU によって処理を切り替える。
コンパイラ差GCC・Clang・Visual C++ でコードを分ける。
機能制限軽量版・製品版で機能を削減する。

特に デバッグコードの切り替え は、
実務でも非常によく登場します。

インデントと可読性の注意点

「あれ? プリプロセッサ命令って、インデントしないの?」

実はこれ、昔からの C 言語文化です。

#ifdef DEBUG
printf("debug\n");
#endif

プリプロセッサ命令は
行頭に書くのが慣習
とされています。

ただし、

  • 多用しすぎる。
  • 入れ子が深くなる。

と、一気に読みにくくなります。

条件付きコンパイルは強力ですが、
使いすぎるとバグの温床になる
ということも覚えておきましょう。

条件付きコンパイルとの上手な付き合い方

条件付きコンパイルは、

  • ビルド時にコードを切り替えられる。
  • 実行ファイルを軽くできる。

という大きなメリットがあります。

一方で、

  • 実行時には確認できない。
  • ソースコードが複雑になりやすい。

という弱点もあります。

基本方針

  • 必要な場面に限定して使う。
  • デバッグ用途に留める。
  • 深い入れ子は避ける。

このバランス感覚が、プロのC言語エンジニアには求められます。