ヘッダファイルのインクルードガード

ヘッダを二重に読み込まれないようにするインクルードガードと呼ばれるテクニックがあります。

たとえば、以下のヘッダファイルは「spvm_field.h」というヘッダファイルですが、インクルードガードのテクニックが使われています。

#ifndef SPVM_FIELD_H
#define SPVM_FIELD_H

#include "spvm_typedef.h"

enum {
  SPVM_FIELD_C_FLAG_PRIVATE = 1,
  SPVM_FIELD_C_FLAG_PUBLIC = 2,
};

struct spvm_field {
  const char* name;
  const char* signature;
  SPVM_TYPE* type;
  SPVM_PACKAGE* package;
  SPVM_OP* op_field;
  SPVM_OP* op_name;
  int32_t id;
  int32_t index;
  int32_t flag;
  int32_t type_category;
  int32_t is_captured;
  int32_t offset;
  int32_t has_setter;
  int32_t has_getter;
};

SPVM_FIELD* SPVM_FIELD_new(SPVM_COMPILER* compiler);

#endif

インクルードガードの部分を取り出してみましょう。

#ifndef SPVM_FIELD_H
#define SPVM_FIELD_H

// ヘッダの内容

#endif

これは、単純なマクロです。プリプロセッサで処理されます。

もし「SPVM_FIELD_H」というマクロが定義されていなかったら「SPVM_FIELD_H」を定義して、ヘッダの内容を読み込むという意味です。

一回目にヘッダファイルが読み込まれたときに「SPVM_FIELD_H」が定義されますので、二回目に読み込まれるときは、ヘッダの内容は読み込まれません。

なぜインクルードガードが必要なの?

ヘッダファイルが二回以上読み込まれる場合の副作用の影響をなくすためです。

たとえば、関数のプロトタイプ宣言は同じものを複数行ってもコンパイルエラーにはなりませんが、enumや構造体の定義を複数回行うと、コンパイルエラーになってしまいます。

そもそも2回以上ヘッダが読み込まれるC言語プログラムってどうなのよ?

はい、おっしゃる通りですね。

ソースコードを分割コンパイルして、ヘッダを1度だけ読み込むようにする。ヘッダどうしでは、できるかぎりヘッダを読み込まない。それが、上手なC言語プログラムだと思います。

ただし、ヘッダでヘッダを読み込みたい場合も、あります。たとえば「stdint.h」をヘッダで読み込んでしまうという場合を挙げておきます。

頻繁に利用するヘッダを、C言語ソースファイル側ではなくって、ヘッダ側で読み込んでおきたいという場合ですね。

#pragma onceはどうですか?

インクルードガードの方法として「#pragma once」を使う方法があります。

#pragma once

コンパイラが対応しているなら、インクルードガードのためのマクロ名を作成する必要がないので、簡単そうです。

「お勧め!」とははっきり僕が言えないのは、広い環境でこのプラグマが対応しているのかどうかを僕が知らないことと、C言語仕様ではなく処理系独自のものだということですね。

マクロを使ったインクルードガードは、不具合なく、どこでも動くと自信を持って言えます。

僕自身は、不確実性をなるべく減らすプログラミング手法を好みますが、ここら辺は、好みなので、あまり気にしないでください。

関連情報