C言語ヘッダーファイルの理解:種類、使い方、ベストプラクティス
ヘッダーファイルは.h拡張子を持つファイルで、複数のソースファイル間で共有するC関数の宣言やマクロ定義を含みます。ヘッダーファイルには、プログラマが自作するファイルと、コンパイラに付属するシステムヘッダーの2種類があります。
プログラムでヘッダーファイルを利用するには、Cプリプロセッサ指令#includeで読み込みます。stdio.hのようにコンパイラ付属のヘッダーを読み込んだ例をすでに見てきました。
ヘッダーファイルをインクルードすることは、その内容をコピーすることと等価ですが、手動でコピーするのはエラーの原因になり、特に複数のソースファイルがある場合は良くない習慣です。
C/C++プログラムでは、定数、マクロ、システム全体のグローバル変数、関数プロトタイプをヘッダーファイルにまとめ、必要な場所でインクルードするのが標準的なプラクティスです。
インクルードの構文
ユーザー作成・システム両方のヘッダーファイルは、プリプロセッサ指令#includeで読み込みます。これには2つの形式があります。
#include <file>
この形式はシステムヘッダーファイル用です。'file'という名前のファイルを、システムディレクトリの標準リストから検索します。コンパイル時に-Iオプションでディレクトリを追加できます。
#include "file"
この形式は自作プログラムのヘッダーファイル用です。'file'を現在のファイルが存在するディレクトリから検索します。こちらも-Iオプションで検索パスを追加可能です。
インクルードの動作
#include指令は、Cプリプロセッサに指定ファイルを入力としてスキャンさせ、その後現在のソースファイルの残りを処理させます。プリプロセッサの出力は、すでに生成された出力、インクルードされたファイルからの出力、#include指令以降のテキストからの出力の順で連結されます。
例えば、header.hが以下の内容だとします。
char *test(void);
このヘッダーを使うprogram.cが以下なら、
int x;
#include "header.h"
int main(void) {
puts(test());
}
コンパイラは以下と同じトークンストリームを見ることになります。
int x;
char *test(void);
int main(void) {
puts(test());
}
多重インクルード防止(ワンオンリー・ヘッダー)
ヘッダーファイルが二重にインクルードされると、コンパイラが内容を二度処理してエラーになります。標準的な防止策は、ファイル全体を条件分岐で囲むことです。
#ifndef HEADER_FILE #define HEADER_FILE /* ヘッダーファイルの実際の内容 */ #endif
この構造は#ifndefラッパーとして知られます。再インクルード時にはHEADER_FILEが定義済みなので条件は偽となり、プリプロセッサはファイル全体をスキップし、コンパイラは二度見ることはありません。
演算インクルード(Computed Includes)
複数のヘッダーファイルからいずれかを選択してインクルードしたい場合があります。例えば、OSごとに異なる設定ヘッダーを使うケースです。条件分岐で書くと:
#if SYSTEM_1 # include "system_1.h" #elif SYSTEM_2 # include "system_2.h" #elif SYSTEM_3 ... #endif
しかし条件が増えると煩雑になります。そこでプリプロセッサは、ヘッダー名にマクロを使える演算インクルード機能を提供します。
#define SYSTEM_H "system_1.h" ... #include SYSTEM_H
SYSTEM_Hが展開され、あたかも#include "system_1.h"と書いたかのように振る舞います。SYSTEM_HはMakefileで-Dオプションにより定義できます。
C言語
- STLファイル理解: 3Dプリントの基盤
- 三角ヤスリの設計・用途・手入れ方法を解説
- ミルファイル(平ヤスリ)完全ガイド:木工・金工の必須工具
- C言語 ファイル入出力: fopen, fprintf, fread, fseek をマスターする
- C言語ファイルI/O完全ガイド:作成、オープン、管理の実践
- C++ファイルI/O完全マスター:fstreamによる読み書き
- C#ファイルI/O:Stream、FileStream、StreamReader/Writerによる読み書き
- VerilogファイルI/Oの完全ガイド:オープン、読み取り、書き込み、クローズ
- PythonファイルI/O:ファイル操作、読み書き、管理のマスター
- PythonファイルI/O:入出力操作をマスターする
- Javaファイル操作のマスター:java.ioによる作成・読み取り・書き込み・削除