#ifndef C にガードを含める

  1. C 言語でヘッダファイルの多重インクルードを防ぐために #ifndef インクルードガードを使用する
  2. マクロが C 言語で複数回定義されないようにするために ifndef ディレクティブを使用する

この記事では、C 言語で #ifndef インクルードガードを使用する方法を複数紹介します。

C 言語でヘッダファイルの多重インクルードを防ぐために #ifndef インクルードガードを使用する

C 言語のヘッダファイルは、同じ名前のソースファイルに実装されている関数のインタフェースを定義するために使用されます。インターフェースには、通常、関数のプロトタイプ、公開されているデータ構造の定義、その他の雑多なものが含まれています。

ヘッダファイルがソースファイルに複数回含まれていると、コンパイラエラーが発生する可能性があることに注意してください。通常、これはラッパーの #ifndef と呼ばれる #ifndef プリプロセッサ指令で防ぐことができます。以下の例では、ヘッダファイルの内容を、#ifndef MY_GUARD ディレクティブが始点、#endif が終点となるような構造で囲んでいます。ifndef ディレクティブは MY_GUARD マクロが定義されているかどうかをチェックし、定義されていなければ次のディレクティブで定義します。ユーザが同じヘッダを 2 回目にインクルードした場合、ifndef ディレクティブは false を評価し、#endif ディレクティブの前のコードを無視します。その結果、コンパイラはこのヘッダファイルからコードのコピーを 1つだけ取得して翻訳に成功します。

#include <stdio.h>

#ifndef MY_GUARD
#define MY_GUARD 1

#define  PER(D) #D
#define  JOIN(A,B) (A ## B)
#define  JOINX(A,B) JOIN(A,B)

int power(int base, int n) {
    int p = base;
    for (size_t i = 0; i < n; i++) {
      p *= base;
    }
    return p;
}
#endif

同じ結果を得るための別の方法として、#pragma once ディレクティブをヘッダファイルに含める方法もあります。プリプロセッサはこれらのヘッダファイルを一度だけスキャンし、二度と読み込まれないことを保証します。以下の方法の欠点は、異なるプリプロセッサ間での移植性が低いということです。

#include <stdio.h>

#pragma once

#define  PER(D) #D
#define  JOIN(A,B) (A ## B)
#define  JOINX(A,B) JOIN(A,B)

int power(int base, int n) {
    int p = base;
    for (size_t i = 0; i < n; i++) {
      p *= base;
    }
    return p;
}

マクロが C 言語で複数回定義されないようにするために ifndef ディレクティブを使用する

あるいは、ifndef ディレクティブを使って、与えられたマクロ式がすでに定義されているかどうかをチェックすることもできます。式が定義されていない場合は、次の #define ディレクティブがそれに応じて処理されます。ifndef#endif の間の行はマクロの定義を 1 行だけにして、条件が false の場合は与えられたマクロの定義だけをスキップします。

#include <stdio.h>
#include <stdlib.h>

#define  PER(D) #D

#ifndef DLEVEL
#define DLEVEL 6
#endif

int main() {

    for (int j = 0; j < DLEVEL; ++j) {
        printf("%s\n", PER(stringify this));
    }

    exit(EXIT_SUCCESS);
}