インクルードガード
CoddyのCジャーニー「Object Oriented Programming」セクションの一部 — レッスン 2/61。
プロジェクト内でヘッダーファイルが複数回インクルードされると、コンパイラは同じ宣言を繰り返し認識し、エラーが発生します。これは、複数のファイルが同じヘッダーをインクルードする場合や、ヘッダー同士が互いにインクルードし合う場合に一般的によく起こります。インクルードガードはこの問題を解決します。
インクルードガードは、ヘッダーの内容が一度だけ処理されるようにするために、3つのプリプロセッサディレクティブを使用します。
// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int add(int a, int b);
#endif
仕組みは次のとおりです。#ifndef MATH_UTILS_H は、シンボル MATH_UTILS_H がまだ定義されていないかどうかをチェックします。定義されていない場合、プリプロセッサは処理を続行し、直ちに #define MATH_UTILS_H でそれを定義します。この箇所から #endif までのすべてがコンパイルに含まれます。
このヘッダーが2回目にインクルードされるとき、MATH_UTILS_H は既に定義されているため、ブロック全体がスキップされます。ガード名は通常、ファイル名を大文字にし、ドットや特殊文字をアンダースコアに置き換えたものになります。
作成するすべてのヘッダーファイルには、インクルードガード(include guards)を設けるべきです。これは、コンパイルエラーを防ぎ、プロジェクト内のどこからでも安全にコードをインクルードできるようにするための標準的な慣行です。
チャレンジ
簡単インクルードガードを追加することで、ヘッダーファイルが二重にインクルードされるのを防ぎましょう。前回のレッスンの挨拶ユーティリティをベースに作成しますが、今回はヘッダーを複数回インクルードしても安全なようにします。
2つのファイルを作成します:
greet.h:greet関数の宣言を含むヘッダーファイルです。今回は、シンボルGREET_Hを使用したインクルードガードで内容全体を囲んでください。main.c: ヘッダーをインクルードし、greet関数を実装し、main()からそれを呼び出すメインファイルです。
greet 関数は、名前を受け取るための const char* 型のパラメータを受け取り、次のように出力する必要があります:
Hello, Alice!ヘッダーファイルは以下の構造に従う必要があります:
#ifndef GREET_H
#define GREET_H
// function declaration here
#endif1つの入力として、名前(文字列)を受け取ります。
上記の形式に従って、Alice を提供された名前に置き換えて、挨拶メッセージを正確に出力してください。
チートシート
インクルードガードは、コンパイル中にヘッダーファイルが複数回処理されるのを防ぎ、エラーの発生を回避します。
インクルードガードは、3つのプリプロセッサディレクティブを使用します:
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// ここにヘッダーの内容を記述します
#endif
#ifndef は、シンボルが定義されていないかどうかをチェックします。未定義の場合、#define がそれを定義し、内容が処理されます。その後のインクルードでは、シンボルがすでに定義されているため、ブロック全体がスキップされます。
ガード名は通常、ファイル名を大文字にし、ドットや特殊文字をアンダースコアに置き換えたものになります。
標準的な慣行として、すべてのヘッダーファイルにインクルードガードを含める必要があります。
自分で試してみよう
#include <stdio.h>
#include "greet.h"
// TODO: "Hello, <name>!" と表示する greet 関数を実装する
int main() {
char name[100];
scanf("%s", name);
// TODO: name を引数にして greet 関数を呼び出す
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。