インクルードをヘッダーファイルまたはソースファイルに配置する必要がありますか?ヘッダーファイルにincludeステートメントが含まれている場合、そのヘッダーファイルをソースに含めれば、ソースファイルにはヘッダーに含まれていたすべてのインクルードファイルが含まれますか?または、ソースファイルにのみ含める必要がありますか?
インクルードをヘッダーファイルまたはソースファイルに配置する必要がありますか?ヘッダーファイルにincludeステートメントが含まれている場合、そのヘッダーファイルをソースに含めれば、ソースファイルにはヘッダーに含まれていたすべてのインクルードファイルが含まれますか?または、ソースファイルにのみ含める必要がありますか?
回答:
ヘッダー自体がヘッダーを必要とする場合にのみ、ヘッダーに組み込みます。
例:
size_t
。次に#include <stddef.h>
、ヘッダーファイルで。strlen
ます。次に#include <string.h>
、ソースファイル内。size_t
ますか?
size_t
場合はstd::string
どうなりますか?
長年にわたってこれについてはかなりの意見の相違がありました。かつては、ヘッダーはそれが関連するモジュールの内容のみを宣言するのが伝統的でした。そのため、多くのヘッダーには#include
、特定のヘッダーセット(特定の順序)が必要でした。一部の非常に伝統的なCプログラマーは、まだこのモデルに従っています(少なくとも一部のケースでは、宗教的に)。
最近では、ほとんどのヘッダーをスタンドアロンにする動きがあります。そのヘッダーに他のものが必要な場合は、ヘッダー自体がそれを処理し、必要なものがすべて含まれるようにします(順序の問題がある場合は正しい順序で)。個人的には、私はこれを好みます-特にヘッダーの順序が重要になる可能性がある場合、それを使用するすべての人に問題の解決を再度要求するのではなく、問題を一度解決します。
ほとんどのヘッダーには宣言のみを含める必要があることに注意してください。つまり、不要なヘッダーを追加しても、(通常は)最終的な実行可能ファイルに影響が及ぶことはありません。最悪の事態は、コンパイルが少し遅くなることです。
あなた#include
のヘッダファイルであること、および各ファイル(ソースまたはヘッダ)すべきであるべきで#include
、それが必要とするヘッダファイルが。ヘッダーファイルは#include
必要最小限のヘッダーファイルである必要があり、ソースファイルも必要ですが、ソースファイルではそれほど重要ではありません。
ソースファイルには、最大のネストの深さまで#include
、ヘッダーとヘッダーが#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コードをコンパイルするには、内部的なものが必要です。
ヘッダーファイルAが#includes
ヘッダーファイルBおよびCである場合、#includes
AのすべてのソースファイルもBおよびCを取得し#included
ます。プリプロセッサは、文字通りテキストの置換を実行します。ファイルを見つける#include <foo.h>
と、foo.h
ファイルのテキストで置き換えるというテキストが見つかります。
#includes
ヘッダーとソースファイルのどちらを使用するかについては、さまざまな意見があります。個人的には、#includes
デフォルトですべてをソースファイルに配置することを好みますが、他の前提条件のヘッダーなしにコンパイルできないヘッダーファイルは、#include
それらのヘッダー自体にする必要があります。
また、すべてのヘッダーファイルにインクルードガードを含めて、複数回インクルードされるのを防ぐ必要があります。
一部の環境では、必要なヘッダーファイルのみが含まれていると、コンパイルが最も高速になります。他の環境では、すべてのソースファイルがヘッダーの同じプライマリコレクションを使用できる場合、コンパイルは最適化されます(一部のファイルには、共通のサブセットを超える追加のヘッダーがある場合があります)。理想的には、複数の#include操作が影響を及ぼさないようにヘッダーを作成する必要があります。#includeステートメントをインクルードされるファイルのインクルードガードのチェックで囲むとよいかもしれませんが、そのガードの形式に依存します。さらに、システムのファイルキャッシング動作によっては、ターゲットが完全に#ifdefされてしまう不要な#includeに時間がかからない場合があります。
考慮すべきもう1つのことは、関数が構造体へのポインタを取得する場合、プロトタイプを次のように書くことができるということです。
void foo(struct BAR_s * bar);
BAR_sの定義がスコープ内にある必要はありません。不要なインクルードを回避するための非常に便利なアプローチ。
PS-私のプロジェクトの多くでは、すべてのモジュールが#includeすることが予想されるファイルがあり、整数サイズのtypedefやいくつかの一般的な構造体および共用体などが含まれます[eg
typedef union { unsigned long l; unsigned short lw [2]; unsigned char lb [4]; } U_QUAD;
(はい、ビッグエンディアンアーキテクチャに移行すると問題が発生することはわかっていますが、私のコンパイラはユニオンで匿名の構造体を許可していないため、ユニオン内のバイトに名前付き識別子を使用すると、次のようにアクセスする必要がありますtheUnion.b.b1などは、かなり煩わしいようです。