C言語のヘッダファイルの二重読み込み防止について紹介します。
ヘッダファイルを何回も読むとどうなるか
C言語は、ヘッダファイルを再帰的に include できます。このため、共通で使う宣言や定義を含んだヘッダファイルは、何回も include されます。別のヘッダファイルが、同じヘッダファイルを include している場合もあります。
同じオブジェクトの定義が重複しても、コンパイラはおおむねうまく処理してくれます。ただし、言語仕様上、同じオブジェクトの重複した定義は、未定義の振る舞いとなり好ましくありません。
ヘッダファイルの再読み込みを防止する定番コードを紹介します。
二重読み込みを防止するコード
ヘッダファイルの最初と最後に、以下の前処理を追加します。
#ifndef THIS_FILE_NAME
#define THIS_FILE_NAME
/* ヘッダファイルの中身 */
#endif /* THIS_FILE_NAME */
THIS_FILE_NAME は、そのファイル名に置き換えます。マクロ定数なので慣用で英字大文字を使います。
ほぼ同じコードですが、以下の書き方を採用する場合もあります。
#if !defiined(THIS_FILE_NAME)
#define THIS_FILE_NAME
/* ヘッダファイルの中身 */
#endif /* THIS_FILE_NAME */
コードは次のように処理されます。
- マクロ定数 THIS_FILE_NAME が定義されない場合(翻訳単位の開始時には、定義されていません)、2行目以降の処理がされます。
- マクロ定数 THIS_FILE_NAME を定義します。
- #endif までヘッダファイル本体の処理がされます。
- 同じ翻訳単位で再びこのヘッダファイルが include された場合は、マクロ定数 THIS_FILE_NAME が定義されています。このため、2行目から最終行(#endif のある行)は、スキップされます。
#if から #endif は長くなることがあります。どの #if と紐づいているかを示すため、#endif のあとにどの条件と紐づいているのかコメントで示しています。よく使われているスタイルです。
コーディングガイドライン
MISRA C 最新版(2023)の Dir 4.10 では、以下の趣旨のガイドラインを紹介しています。
ヘッダファイルが複数回読み込まれないようにしよう
このテクニックは、昔からよく使われていました。それを明文化したガイドラインとなっています。
最後に
AUTOSAR では、プログラムのセクションを示すために、複数回読まれることを前提としたヘッダファイルを導入しています。個人的に MemMap ファイルと呼んでいます。このような例外はありますが、特別な事情がない限り、二重読み込み防止をしたほうがよいでしょう。
C言語を使いこなしていきましょう!