0Pricing
C Academy · レッスン

インクルードガード

二重インクルードを防ぎます。

「インクルードガード」はCoddyKit上の無料C Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。

二重インクルードの問題

ヘッダーが他のヘッダーをインクルードすることはよくあります。そのため、1つのソースファイルに同じヘッダーが2回インクルードされることがあります。

そうなると、ヘッダー内のすべての宣言が2回現れます。structやtypedefなどの型定義では、型を複数回定義できないためコンパイルエラーになります。

どのように発生するのか

a.hとb.hがどちらもtypes.hをインクルードするとします。両方をインクルードするソースファイルでは、types.hが2回貼り付けられた状態になります。

プリプロセッサはヘッダーのテキストをそのままコピーするため、types.hの定義が重複し、再定義エラーが発生します。

/* a.h */ #include "types.h"
/* b.h */ #include "types.h"
/* main.c */
#include "a.h"
#include "b.h"   /* types.h now seen twice */

インクルードガード

インクルードガードは、ヘッダーを何度も安全にインクルードできるようにする、簡単なプリプロセッサの仕組みです。

ヘッダー全体を条件付きの処理で囲み、本体が最初の1回だけ処理されるようにします。それ以降のインクルードは完全にスキップされます。

#ifndef TYPES_H
#define TYPES_H

/* header contents here */

#endif /* TYPES_H */

ガードの仕組み

ヘッダーが最初に読み込まれたとき、TYPES_Hは未定義なので、#ifndefは真になり、本体が処理されます。その後、#defineによってマクロが設定されます。

次回以降のインクルードでは、TYPES_Hがすでに存在するため、#ifndefは偽になり、プリプロセッサは#endifまでスキップします。

#ifndef TYPES_H   /* true only the first time */
#define TYPES_H   /* remember we've been here */
/* ... body ... */
#endif

完全なガード付きヘッダー

ここでは、型定義をガードで保護した実用的なヘッダーを示します。

多くのファイルがpoint.hを直接または間接的にインクルードしても、各翻訳単位でPoint構造体が定義されるのは1回だけです。

/* point.h */
#ifndef POINT_H
#define POINT_H

typedef struct {
    int x;
    int y;
} Point;

Point point_add(Point a, Point b);

#endif

マクロ名の選び方

ガードマクロはプロジェクト全体で一意でなければなりません。そうでないと、2つのヘッダーが衝突し、互いの内容を気付かないうちに隠してしまうことがあります。

ファイル名から大文字で名前を作るのが一般的です。point.hはPOINT_H、net/socket.hはNET_SOCKET_Hになります。

#ifndef NET_SOCKET_H
#define NET_SOCKET_H
/* ... */
#endif

予約名を避ける

大文字の後に続くアンダースコアで始まる識別子や、2つのアンダースコアを含む識別子は、コンパイラと標準ライブラリのために予約されています。

__POINT_H__のようなガードは避けてください。POINT_Hのように末尾にアンダースコアを付ける形式は安全で分かりやすい名前です。

#ifndef _POINT_H_   /* risky: reserved name pattern */
#ifndef POINT_H     /* preferred */

#pragma onceという代替手段

現在の多くのコンパイラは#pragma onceをサポートしています。これはヘッダーの先頭に1行記述するだけで、同じ役割を果たします。

短く書けて名前の衝突も避けられますが、C標準の一部ではありません。従来の#ifndefガードはどの環境でも機能します。

/* point.h */
#pragma once

typedef struct { int x; int y; } Point;

ガードとプラグマの比較

#ifndefガードは完全に移植可能で標準的ですが、ヘッダーごとに一意なマクロが必要です。

#pragma onceは簡潔で衝突も起こりませんが、コンパイラのサポートに依存します。安全性を最大限に高めるため、プラグマと従来のガードの両方を使うプロジェクトもあります。

#pragma once
#ifndef POINT_H
#define POINT_H
/* ... */
#endif

ガードは翻訳単位ごとに機能する

インクルードガードは、ソースファイルをコンパイルする際に、同じソースファイル内での重複インクルードを防ぎます。

ただし、別々の.cファイルでヘッダーがそれぞれ1回ずつ処理されることは防ぎません。これは問題ありません。各ソースファイルは別個の翻訳単位だからです。

習慣にする

作成するすべてのヘッダーに、最初の行からインクルードガードを追加してください。3行分の手間で、分かりにくいエラーの多くを防げます。

単純なヘッダーでも、後から別のヘッダー経由で間接的にインクルードされることがあります。最初からガードを付けておけば、トラブルを避けられます。

/* config.h */
#ifndef CONFIG_H
#define CONFIG_H
#define MAX_USERS 100
#endif

理解度チェック

インクルードガードについて、理解度を確認しましょう。

まとめ

ヘッダーを2回インクルードすると再定義エラーが発生する理由と、インクルードガードでそれを防ぐ方法を学びました。

一意のマクロを使って#ifndef/#define/#endifを記述するか、#pragma onceを使います。次は、externを使ってファイル間で変数を共有する方法を見ていきます。

よくある質問

「インクルードガード」レッスンは無料ですか?

はい。「インクルードガード」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「インクルードガード」で何を学びますか?

二重インクルードを防ぎます。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「インクルードガード」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC Academyレッスンでコードを書いて実行できますか?

はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ヘッダーファイルとソースファイル
  2. インクルードガード
  3. externとリンケージ
  4. 複数ファイルをコンパイルする
← C Academyに戻る