本文へスキップ
BecomeCoder

C言語コース · 第9章 プリプロセッサ · レッスン37

#include と #ifdef/#ifndef ― 条件コンパイル

ブラウザで完結

導入

開発中はデバッグ用の printf をたくさん入れたいけれど、完成版ではそれらを全部消したい……という場面はよくあります。行ごとコメントアウト/インするのは面倒です。#ifdef/#ifndef を使うと、「ある名前が定義されているかどうか」で、コードの一部をコンパイルに含めるかどうかを丸ごと切り替えられます。

説明

#include <stdio.h> は「そのファイルの内容をこの場所にそのまま貼り込む」というプリプロセッサ指令でした。同じように #ifdef 名前 は「名前#define されていれば、対応する #endif までの行をコードに含める」という指令です。反対に #ifndef 名前 は「名前#define されていなければ含める」という意味になります。

#include <stdio.h>

#define DEBUG

int main(void) {
    int x = 10;
#ifdef DEBUG
    printf("[DEBUG] x = %d\n", x);
#endif
    printf("結果: %d\n", x * 2);
    return 0;
}

#define DEBUG の行があるので DEBUG は定義済みです。すると #ifdef DEBUG から #endif までの printf がコンパイルに含まれ、実行結果には [DEBUG] x = 10 が出力されます。もし先頭の #define DEBUG を消すと、DEBUG は定義されていないので、その printf はコンパイルの時点で丸ごと存在しないのと同じになり、実行時に一切出てきません。

flowchart TB
  d{"DEBUG は #define 済み?"}
  d -->|"はい (#ifdef)"| a["[DEBUG]の行をコードに含める"]
  d -->|"いいえ"| b["[DEBUG]の行はコンパイル対象から除外"]

#else を組み合わせると、「定義されているとき/されていないとき」の両方を書けます。

#include <stdio.h>

#define MODE_DEBUG

int main(void) {
#ifdef MODE_DEBUG
    printf("デバッグモード\n");
#else
    printf("リリースモード\n");
#endif
    return 0;
}

if/else と似ていますが、大きな違いがあります。if/else実行時にどちらを実行するか決まるのに対し、#ifdef/#elseコンパイルされる前にどちらのコードを含めるかが決まり、含まれなかった側は実行ファイルに一切残りません。

やってみよう

#define DEBUG の行をコメントアウトして、デバッグ出力が消えることを確かめましょう。MODE_DEBUG の例も、#define の行を消して #else 側が実行されることを確認してください。

演習

#define SHOW_EXTRA を使って、SHOW_EXTRA が定義されているときだけ 追加情報\n を表示し、常に 基本情報\n を表示するプログラムを書いてください(SHOW_EXTRA を定義した状態で実行すると両方表示されます)。

ヒント1を見る

先頭に #define SHOW_EXTRA を書きます。

ヒント2を見る

#ifdef SHOW_EXTRA から #endif の間に printf("追加情報\n"); を置きます。

実際に動かしてみよう

下のエディタにCを書いて「実行」を押すと、ブラウザ内のインタプリタで出力が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう(scanf を使う回は「標準入力」欄に値を入れてから実行します)。

C/C++ — ブラウザ内で実行

ブラウザ内でC/C++を動かす学習用インタプリタ(JSCPP)を読み込みます(入門向けのサブセットです)。
スクロールして表示された時点でも自動で読み込まれます。