C/C++の分割コンパイルの際に使えそうな小技「予防的インクルードガード」を考案したので紹介しておきます.
もしかしたら既存とか非合法かもしれませんが,特定のヘッダファイルの間接インクルードを阻止しちゃうぞ,っというものです.
プロローグ
ソースファイル
// ihihi.cです.ufufu.hちゃん狙いなんだけど...
// 同行予定のahaha.hが邪魔なので工夫してみた.
#define AHAHA_H // 予防的インクルードガード!!
// ahaha.hはすでに来たことにする
#include "ufufu.h"
// ahaha.hちゃんは先に来てるよー😎
// ufufu.hちゃんも急いで来てねー😃
// ぐへへー
...
ちょっとヤバめなソースですね.
ヘッダファイルたち
// ufufu.hです.ihihi.cさんからの猛烈なお誘いを断りきれず...
#ifndef UFUFU_H // 一度だけならとOKしちゃったけど...😥
#define UFUFU_H
#include "ahaha.h" // 💡ahaha.hちゃんとご一緒しますね
...
#endif
標準的な#defineガード付きのヘッダですね.
他のヘッダを間接インクルードしています.
// ahaha.hでーす.ufufu.hちゃんより頑張っちゃうぞー😃
#ifndef AHAHA_H // false ==> って,いきなり出禁かよ😑
#define AHAHA_H
...
#endif
ヘッダ側の間接インクルードがソース側から阻止されました.
使い道あるん?
ヘッダとソースの間の重複定義の回避に使えますよ.
// A.hh
#ifndef A_HH
#define A_HH
...
extern int func(int x = 0);
...
#endif
// B.hh
#ifndef B_HH
#define B_HH
#include "A.hh" // 間接インクルード
...
#endif
// A.cc
#define A_HH // 予防的ガード
#include "B.hh"
int func(int x = 0) { ... } // コレって普通なら二重定義じゃね?
...
もし予防的ガードがないと,ソースA.ccのコンパイル時にA.hhがインクルードされるので,両者に含まれる関数func()のデフォルト引数x = 0が二重定義エラーとなってしまいます.
[2025.09.16追記] 不備発見.
A.cc内のコードの順序が変でした.
B.hhがA.hhに依存している場合,未定義エラーが発生しますね.
int func(...)など,A.hh内のコードの代替となるものについては,#include "B.hh"より先に書くべきです.m(_ _;)m
普通の回避策としては,ソース側で削除とかコメント化が必要となります.
...
int func(int x /* = 0 */) { ... } // こんな苦肉の策はヤメてー
...
ちなみに,普通ならヘッダ側へ移設しておくべきクラス・マクロ等の定義についてもソース側に残しておけますよ.
#pragmaガードとの合わせ技
// file.hでございます.
#pragma once // お呼びがあれば一度限りですが参ります
#ifndef FILE_H // もし,お邪魔でしたら参りません
...
#endif // 失礼いたしました
多重インクルードの場合,ファイル入力の回数を減らせるので,コンパイルが多少は軽量化されるかもしれません.
#define FILE_Hは不要です.必要に応じてソース側で定義します.
AIによる評価
Google「インクルードガード ソースファイル」の検索結果:
✦AI による概要
インクルードガードとは、ヘッダファイルを複数回インクルードすることによるコンパイルエラー(再定義エラー)を防ぐための仕組みです。インクルードガードはヘッダファイル内に記述し、一度もインクルードされていなければインクルードを許可し、すでにインクルードされている場合はインクルードをスキップすることで、ヘッダファイルの内容が重複して処理されることを防ぎます。
(中略)
ソースファイルにおけるインクルードガードの利用
ソースファイルではヘッダファイルをインクルードして、ヘッダファイルで宣言された関数や構造体を定義します。インクルードガードは、インクルードするヘッダファイルそのものの内容の重複を防ぐための仕組みであり、ソースファイルで直接インクルードガードを記述する必要はありません。
🎉 異端認定を頂戴しました.ありがとうございます.
エピローグ
// ihihi.c: 実は,ahaha.hちゃんが来れないように細工してたんだ...
// ufufu.h: どうして,ahaha.hちゃんはダメなの?
// ihihi.c: 二重定義の危険があるからね.
// ufufu.h: えー,もうインクルードしちゃってたってこと?いつの間に?
// ihihi.c: インクルードなんてしてないよ.
// ufufu.h: え,そーなの?
// ihihi.c: ahaha.hちゃんのことは俺とは別のソースが必要としてくれるハズさ.
// ufufu.h: よくわかんない...
// ihihi.c: そんなことより,もう一度?
そして静かにインクルードガードが発動したのであった.