インクルードガード: 定義の保護

「このファイルは一回読んだよね?」ヘッダファイルの重複読み込みを防ぐ改札口。

インクルードガード
ヘッダファイルが複数回読み込まれるのを防ぐための記述。
ヘッダファイル (.h)
関数の宣言や構造体の定義などを書くファイル。
#pragma once
インクルードガードを1行で書ける便利な機能。現代のコンパイラなら大抵使える。
再入場のハンドスタンプ (The Hand Stamp)

インクルードガードは、テーマパークの「再入場のハンドスタンプ」です。 最初にファイルを読み込むとき(入場)、手の甲にスタンプ(#define)を押します。 もし別の場所からまた同じファイルを読み込もうとしても(再入場)、スタンプがある(#ifdef)のを見て「君はもう中に入ってるね」と判断され、中身をスキップされます。 これがないと、同じ人が何人も分身して入場してしまい、大混乱(二重定義エラー)になります。

二重定義を防ぐ

C言語では、1つのソースファイル内で同じ構造体を2回定義するとエラーになります。大規模なプロジェクトでは、「A.hの中にB.hをinclude」し、「main.cでA.hとB.hをinclude」すると、B.hの中身が2回展開されてしまいます。

インクルードガードは、「もしこのファイルがまだ読まれていなかったら読む。読まれていたらスキップする」という制御を行うための仕組みです。

書き方

伝統的な書き方 (The Standard)

どんなCコンパイラでも確実に動く方法です。ユニークな名前(ファイル名_Hなど)を定義します。

Standard Guard
// header.h (ガードあり)
#ifndef HEADER_H
#define HEADER_H
struct Point { int x, y; };
#endif // HEADER_H

現代的な書き方 (#pragma once)

最近のコンパイラ(GCC, Clang, MSVC)ならこれでOKです。名前を考える必要がなく、ミスも減ります。

#pragma once
// header.h (現代的)
#pragma once
struct Point { int x, y; };

実践テクニック

循環参照に注意

「A.hがB.hを読み、B.hがA.hを読む」という状態は、インクルードガードがあっても解決できません(コンパイルエラーになります)。こういう場合は設計を見直すか、前方宣言 (Forward Declaration) を使って解決します。

演習課題

課題1: ガードの実装
構造体を持つヘッダファイルを作り、main.cで2回includeしてもエラーにならないようにインクルードガードをつけてください。

合格ライン

#ifndef ~ #endif の流れを書ける
#pragma once の便利さを知っている