PRE06-C. ヘッダファイルはインクルードガードで囲む
1980年代初頭まで、大規模なソフトウェア開発プロジェクトはヘッダのインクルードについて度重なる問題に遭遇していた。たとえば、あるグループが graphics.h
を作成し、このヘッダの冒頭で io.h
をインクルードする。一方、他のグループが keyboard.h
を作成し、これもまた io.h
をインクルードする。もし io.h
を安全に複数回インクルードすることができなければ、どのヘッダが io.h
をインクルードするべきかという議論が起こる。あるアプリケーションプログラムの例では、どのヘッダも他のヘッダを一切インクルードしてはならないという取り決めがされ、プログラムコードは数十もの #include
行から始まることになった。その結果、インクルードの順序を間違えたり、必要なヘッダを忘れてしまったりという問題が発生した。
適合コード
これらの混乱は単純な手法の発見により解決した。それは、各ヘッダで「自分はすでにインクルードされています」を意味するシンボルを定義する(#define
する)という方法である。ヘッダ全体を次のようにインクルードガードで囲むのである。
#ifndef HEADER_H
#define HEADER_H
/* ... <header.h> の内容がここに入る */
#endif /* HEADER_H */
これにより、header.h
は最初の #include
でその内容がすべてインクルードされる。このヘッダが続いてもう一度 #include
されると、その内容はバイパスされる。
このような方法を使うことで複数回インクルードできるヘッダファイルを作成できる。C標準では、標準ヘッダは複数回インクルードされても安全であることを保証している。
インクルードガードで使用するマクロの名前に予約済みの識別子を使用するのはよくある誤りであり、注意が必要である。「DCL37-C. 予約済みの識別子を宣言または定義しない」を参照。
リスク評価
ヘッダファイルをインクルードガードで囲み忘れると予期せぬ動作を引き起こすおそれがある。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
PRE06-C |
低 |
低 |
低 |
P3 |
L3 |
自動検出
ツール | バージョン | チェッカー | 説明 |
---|---|---|---|
Astrée |
17.04i
|
multiple-include | 一部実装済み |
1.2
|
CC2.PRE06 |
実装済み | |
Klocwork |
2017
|
MISRA.INCGUARD |
|
LDRA tool suite |
9.7.1
|
243 S |
実装済み |
Parasoft C/C++test | 10.3 | PFO-02 | 実装済み |
PRQA QA-C |
9.3
|
0883 | 実装済み |
RuleChecker |
17.04i
|
multiple-include | 一部実装済み |
関連するガイドライン
SEI CERT C++ Coding Standard | VOID PRE06-CPP. Enclose header files in an include guard |
MISRA C:2012 | Directive 4.10 (required) |
参考資料
[Plum 1985] | Rule 1-14 |
翻訳元
これは以下のページを翻訳したものです。
PRE06-C. Enclose header files in an include guard (revision 92)