ヘッダーファイルまたはソースファイルにインクルードを配置する必要がありますか?ヘッダーファイルにincludeステートメントが含まれている場合、そのヘッダーファイルをソースに含めると、ソースファイルにはヘッダーに含まれていたすべてのインクルードファイルが含まれますか?または、ソースファイルのみに含める必要がありますか?
ヘッダー自体に必要な場合にのみ、ヘッダーにインクルードを配置します。
例:
size_t
型を返します。次に、ヘッダーファイルの#include <stddef.h>
.strlen
を使用します。次に、ソースファイル内の#include <string.h>
。これについては長年にわたってかなりの意見の相違がありました。かつては、ヘッダーonlyが関連するモジュールの内容を宣言するのが伝統的であったため、manyヘッダーには特定の要件がありました#include
特定のヘッダーセット(特定の順序)。一部の非常に伝統的なCプログラマーは、このモデルを引き続き使用します(少なくとも、場合によっては厳密に)。
最近では、ほとんどのヘッダーをスタンドアロンにしようとする動きがあります。そのヘッダーが他の何かを必要とする場合、ヘッダー自体がそれを処理し、必要なものが含まれるようにします(順序の問題がある場合は正しい順序で)。個人的には、私はこれを好む-特にヘッダーの順序が重要になる可能性がある場合、それを使用するすべての人にもう一度問題を解決するよう求めるのではなく、問題を一度解決する。
ほとんどのヘッダーには宣言のみを含める必要があることに注意してください。これは、不要なヘッダーを追加しても、(通常)最終的な実行可能ファイルに影響しないことを意味します。最悪の事態は、コンパイルが少し遅くなることです。
きみの #include
sはヘッダーファイルである必要があり、各ファイル(ソースまたはヘッダー)は#include
必要なヘッダーファイル。ヘッダーファイルは#include
必要最小限のヘッダーファイル、およびソースファイルも必要ですが、ソースファイルにとってはそれほど重要ではありません。
ソースファイルにはヘッダーがあります#include
s、およびそれらのヘッダー#include
など、最大のネストの深さまで。これが、余分な#include
sヘッダーファイル:ソースファイルに必要のないヘッダーファイルが多く含まれることがあり、コンパイルが遅くなります。
これは、ヘッダーファイルが2回インクルードされる可能性が完全にあり、それが問題になる可能性があることを意味します。従来の方法は、foo.hファイルの場合のように、ヘッダーファイルに「ガードを含める」ことです。
#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif
私が20年以上にわたって進化させてきたアプローチがこれです。
ライブラリを検討してください。
複数のCファイルがあり、1つの内部Hファイルと1つの外部Hファイルがあります。 Cファイルには内部Hファイルが含まれます。内部Hファイルには、外部Hファイルが含まれます。
コンパイラーPOVから、Cファイルをコンパイルするときに階層があることがわかります。
外部->内部-> Cコード
これは正しい順序です。外部のものが、ライブラリを使用するためにサードパーティが必要とするすべてであるためです。 Cコードをコンパイルするには、内部のものが必要です。
一部の環境では、必要なヘッダーファイルのみを含めるとコンパイルが最速になります。他の環境では、すべてのソースファイルがヘッダーの同じプライマリコレクションを使用できる場合、コンパイルが最適化されます(一部のファイルには、共通のサブセットを超える追加のヘッダーがある場合があります)。理想的には、複数の#include操作が効果を及ぼさないようにヘッダーを構築する必要があります。 #includeステートメントをインクルード対象ファイルのインクルードガードのチェックで囲むとよい場合がありますが、その場合、そのガードの形式に依存します。さらに、システムのファイルキャッシング動作によっては、ターゲットが完全に#ifdef'edされることになってしまう不要な#includeに時間がかかりません。
考慮すべきもう1つのことは、関数が構造体へのポインタをとる場合、プロトタイプを
void foo(struct BAR_s * bar);
bAR_sの定義がスコープ内にある必要はありません。不要なインクルードを回避するための非常に便利なアプローチ。
PS-私のプロジェクトの多くでは、すべてのモジュールが#includeを含むと予想されるファイルがあります。これには、整数サイズのtypedefやいくつかの一般的な構造体と共用体などが含まれます[e.g.
typedef union { unsigned long l; unsigned short lw [2]; unsigned char lb [4]; } U_QUAD;
(はい、ビッグエンディアンアーキテクチャに移行すると問題が発生することはわかっていますが、コンパイラはユニオンで匿名構造体を許可しないため、ユニオン内のバイトに名前付き識別子を使用するには、次のようにアクセスする必要がありますtheUnion.b.b1など。
ヘッダーファイルA #includes
ヘッダーファイルBおよびCの場合、#includes
AであるすべてのソースファイルもBおよびC #included
を取得します。プリプロセッサは文字通りテキスト置換を実行します。#include <foo.h>
というテキストを見つけると、foo.h
ファイルのテキストに置き換えます。
#includes
をヘッダーとソースファイルのどちらに入れるべきかについては、さまざまな意見があります。個人的には、すべての#includes
をデフォルトでソースファイルに配置することを好みますが、他の前提条件ヘッダーなしではコンパイルできないヘッダーファイルは、それらのヘッダー自体を#include
する必要があります。
また、すべてのヘッダーファイルには、複数回インクルードされないようにインクルードガードを含める必要があります。
すべてのファイルを作成して、含まれているものだけを使用してビルドできるようにします。ヘッダーに含める必要がない場合は、削除します。大きなプロジェクトでは、この規律を維持しないと、誰かがヘッダーではなく、そのファイルのコンシューマーによって使用されているヘッダーファイルからインクルードを削除しても、ビルド全体を壊すことになります。
定数と関数宣言を宣言する必要があるファイルのみをヘッダーに含める必要があります。技術的には、これらのインクルードもソースファイルに含まれますが、明確にするために、実際に使用する必要があるファイルのみを各ファイルに含める必要があります。また、ヘッダー内の複数のインクルードからこれらを保護する必要があります。
#ifndef NAME_OF_HEADER_H
#define NAME_OF_HEADER_H
...definition of header file...
#endif
これにより、ヘッダーが複数回インクルードされなくなり、コンパイラエラーが発生しなくなります。
ソースファイルには、ヘッダーに含めるとincludeステートメントが含まれます。ただし、場合によっては、ソースファイルに配置した方がよい場合があります。
そのヘッダーを他のソースに含めると、ヘッダーからインクルードも取得されることに注意してください。これは常に望ましいとは限りません。使用するものだけを含める必要があります。