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 ());
}
ヘッダファイルの役割
C 言語では、各ソース ファイルはモジュールであり、ヘッダー ファイルはモジュールを使用するユーザーにインターフェイスを提供します。インターフェイスとは、機能モジュールが特定の機能にアクセスするために他のモジュールに公開するメソッドを指します。
ソース ファイルを使用してモジュールの機能を実装し、ヘッダー ファイルを使用してユニットのインターフェイスを公開します。ユーザーは、対応するヘッダー ファイルをインクルードするだけで、ヘッダー ファイルで公開されているインターフェイスを使用できます。
ヘッダー ファイルに含まれるメソッドを使用してプログラム内の各機能モジュールをリンクすると、モジュラー プログラミング設計に役立ちます。
1) ヘッダー ファイルを介してライブラリ関数を呼び出します。多くの場合、ヘッダー ファイルとバイナリ ライブラリがユーザーに提供されている限り、ソース コードをユーザーに公開することは不便 (または許可されない) です。ユーザーは、ヘッダー ファイルのインターフェイス宣言に従ってライブラリ関数を呼び出すだけでよく、インターフェイスがどのように実装されているかを気にする必要はありません。コンパイラは、対応するコードをライブラリから抽出します。
2) ヘッダー ファイルは型の安全性チェックを強化できます。インターフェイスがヘッダー ファイルの宣言と矛盾する方法で実装または使用されている場合、コンパイラはエラーを指摘します。この単純なルールにより、プログラマーのデバッグとエラー修正の負担を大幅に軽減できます。
コンパイラは、前処理段階で、ソース ファイルに含まれているヘッダー ファイルの内容をインクルード ステートメント (#include) にコピーします。ソースファイルをコンパイルすると、インクルードされたヘッダーファイルの内容と一緒にコンパイルされ、オブジェクトファイル (.obj) が生成されます。
インクルードされたヘッダー ファイルが非常に大きい場合、コンパイル速度が大幅に低下します (GCC の -E オプションを使用して、前処理された最終的なファイルを取得して表示します)。したがって、必要なヘッダー ファイルのみをソース ファイルに含める必要があり、ヘッダー ファイルに他のヘッダー ファイルを含めないようにしてください。
ヘッダー ファイル構成の原則
変数と関数の定義はソース ファイルに実装され、リンク スコープが指定されます。ヘッダー ファイルには、外部で使用する必要があるグローバル変数、関数宣言、データ型、およびマクロの定義を記述します。
ヘッダー ファイルの内容を整理するには、次のガイドラインに従うことをお勧めします。
- ヘッダーファイル分割の原則: 型定義とマクロ定義は関数宣言からできるだけ分離し、別のヘッダーファイルに配置する必要があります。内部関数宣言ヘッダー ファイルは外部関数宣言ヘッダー ファイルから分離され、内部型定義ヘッダー ファイルは外部型定義ヘッダー ファイルから分離されます。
型とマクロの定義を異なるファイルに分割できない場合があることに注意してください。たとえば、構造体の配列メンバーの要素数が定数マクロで表される場合などです。したがって、型マクロ定義と関数宣言のみが分離され、それぞれ *.th および *.fh ファイルに配置されます (必須ではありません)。
-
ヘッダー ファイルのセマンティック階層の原則: ヘッダー ファイルにはセマンティック階層が必要です。異なるセマンティック レベルの型定義を 1 つのヘッダー ファイルに配置したり、異なるレベルの関数宣言を 1 つのヘッダー ファイルに配置したりしないでください。
-
ヘッダー ファイルのセマンティック関連性の原則: 同じヘッダー ファイルに表示される型定義と関数宣言は、セマンティックに関連し、内部論理関係を持つ必要があり、無関係な定義と宣言を 1 つのヘッダー ファイルに入れないようにします。
-
ヘッダー ファイルの名前は、関数を実装するソース ファイル、つまり module.c および module.h と同じにする必要があります。ただし、ソース ファイルに同じ名前のヘッダー ファイルを含める必要はありません。
-
モジュール間の結合を減らすために、ヘッダー ファイルにローカル データを含めないでください。
つまり、ソース ファイル自体で使用される型、マクロ定義、変数、および関数宣言のみがヘッダー ファイルに表示されないようにする必要があります。スコープが 1 つのファイルに限定されているプライベート変数と関数は、外部呼び出しを防ぐために static として宣言する必要があります。ソース ファイルにプライベート タイプを配置すると、まとまりが増し、不要な書式の漏れが減少します。 -
ヘッダー ファイルで変数と関数を定義することはできません。マクロ、型 (typedef/struct/union/enum など)、および変数と関数の宣言のみを定義できます。
特殊なケースでは、基本型のグローバル変数を extern にすることができ、ソース ファイルはヘッダー ファイルをインクルードすることでグローバル変数にアクセスできます。ただし、ヘッダー ファイルは、カスタム型 (構造体など) のグローバル変数を extern にしないでください。そうしないと、変数にアクセスする必要のないソース ファイルに、カスタム型が配置されているヘッダー ファイル [1] を含めるように強制されます。 . -
記述ヘッダー ファイルには、対応するソース ファイルが必要ではありません。これらのヘッダー ファイルのほとんどには、多数の概念的なマクロ定義または列挙型定義が含まれており、他の型定義および変数または関数の宣言は含まれていません。このようなヘッダー ファイルには、他のヘッダー ファイルも含めないでください。
-
#pragma once またはヘッダー ガード (インクルード ガードまたはマクロ ガードとも呼ばれます) を使用して、ヘッダー ファイルが繰り返し含まれないようにします。#pragma once は非標準ですが、最新のコンパイラで広くサポートされているトリックであり、プリプロセッサに「現在のヘッダー ファイルを二重にインクルードしない」ように明示的に指示します。ヘッダー ガードは、前処理コマンドを通じて同様の動作をシミュレートします。
#pragma once を使用すると、ヘッダー ガードよりも 2 つの利点があります。
①より速く。コンパイラは、#pragma とマークされたファイルを 2 回目に読み取ることはありませんが、ヘッダー ガードを使用してファイルを数回読み取ります (#endif を探します)。
②簡単に。各ファイルのヘッダー ガードに名前を付ける必要がなくなり、重複するマクロ名によって引き起こされる「宣言が見つからない」という問題が回避されます。
欠点は次のとおりです。
#pragma once保证物理上的同一个文件不会被包含多次,无法对头文件中的一段代码作#pragma once声明。若某个头文件具有多份拷贝(内容相同的多个文件),pragma不能保证它们不被重复包含。当然,这种重复包含很容易被发现并修正。
- C++ で C 関数を参照する場合、関数が配置されているヘッダー ファイルに extern "C" を含める必要があります。
extern "C" によって変更された変数と関数は、C 言語でコンパイルおよびリンクされます。そうしないと、コンパイラは C 関数定義を見つけることができず、リンク エラーが発生します。
- アプリケーションの観点からインターフェイスによって公開されるコンテンツを説明するために、ヘッダー ファイルには十分なユーザー指向のコメントが必要です。