includeステートメント、ヘッダー、またはソースをどこに配置しますか?


106

インクルードをヘッダーファイルまたはソースファイルに配置する必要がありますか?ヘッダーファイルにincludeステートメントが含まれている場合、そのヘッダーファイルをソースに含めれば、ソースファイルにはヘッダーに含まれていたすべてのインクルードファイルが含まれますか?または、ソースファイルにのみ含める必要がありますか?


2
SOでの以前の多くの複製、たとえば「インクルード」はC ++に配置する必要がある場所
Paul R

回答:


141

ヘッダー自体がヘッダーを必要とする場合にのみ、ヘッダーに組み込みます。

例:

  • 関数はtypeを返しますsize_t。次に#include <stddef.h>ヘッダーファイルで。
  • 関数はを使用しstrlenます。次に#include <string.h>ソースファイル内。

2
関数が型の引数を取る場合はどうなりsize_tますか?
andrybak 2013年

同じ質問がc ++に拡張されます:構造体/クラスに型のフィールド/メンバーがあるsize_t場合はstd::stringどうなりますか?
andrybak 2013年

10
根拠は何ですか?
Patrizio Bertoni

私は有線の状況にあり、C ++クラスAには別のクラスBのオブジェクトがあり、Bの前方宣言とAヘッダー内のBヘッダーを含む終了を使用できません。(ポインターを使用してもこの問題はありません)
shuva 2017

@andrybakソースファイルにはヘッダーファイルを含める必要があるため、ヘッダーが含まれていれば、ソースも取得します。
Jeremy Trifilo

27

長年にわたってこれについてはかなりの意見の相違がありました。かつては、ヘッダーはそれが関連するモジュールの内容のみを宣言するのが伝統的でした。そのため、多くのヘッダーには#include、特定のヘッダーセット(特定の順序)が必要でした。一部の非常に伝統的なCプログラマーは、まだこのモデルに従っています(少なくとも一部のケースでは、宗教的に)。

最近では、ほとんどのヘッダーをスタンドアロンにする動きがあります。そのヘッダーに他のものが必要な場合は、ヘッダー自体がそれを処理し、必要なものがすべて含まれるようにします(順序の問題がある場合は正しい順序で)。個人的には、私はこれを好みます-特にヘッダーの順序が重要になる可能性がある場合、それを使用するすべての人に問題の解決を再度要求するのではなく、問題を一度解決します。

ほとんどのヘッダーには宣言のみを含める必要があることに注意してください。つまり、不要なヘッダーを追加しても、(通常は)最終的な実行可能ファイルに影響が及ぶことはありません。最悪の事態は、コンパイルが少し遅くなることです。


2
すべてのヘッダーが2番目のスタイルで記述されている場合、順序の問題はまったくありません。ヘッダーに順序付けの問題があることは、通常、ヘッダーに必要なものがすべて含まれていないことを意味します。
さようならSE

12

あなた#includeのヘッダファイルであること、および各ファイル(ソースまたはヘッダ)すべきであるべきで#include、それが必要とするヘッダファイルが。ヘッダーファイルは#include必要最小限のヘッダーファイルである必要があり、ソースファイルも必要ですが、ソースファイルではそれほど重要ではありません。

ソースファイルには、最大のネストの深さまで#include、ヘッダーとヘッダーが#includeあります。これが#include、ヘッダーファイルに余分なsを必要としない理由です。これにより、ソースファイルに不要な多くのヘッダーファイルが含まれ、コンパイルが遅くなる可能性があります。

つまり、ヘッダーファイルが2度インクルードされる可能性があり、それが問題になる可能性があります。従来の方法は、ファイルfoo.hの場合のように、ヘッダーファイルに「ガードを含める」ことです。

#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
/* everything in header goes here */
#endif

私はこの答えが超古いことを知っていますが、それ以来#pragmaを一度追加したので、#includesを宣言するときに#ifndefを含めるかどうかはわかりません。
Dogunbound猟犬

6

私が20年以上にわたって進化させてきたアプローチはこれです。

ライブラリを検討してください。

複数のCファイルがあり、1つの内部Hファイルと1つの外部Hファイルがあります。Cファイルには内部Hファイルが含まれます。内部Hファイルには外部Hファイルが含まれます。

コンパイラのPOVから、Cファイルをコンパイルするときに階層があることがわかります。

外部->内部-> Cコード

外部のものがライブラリを使用するためにサードパーティが必要とするすべてのものであるため、これは正しい順序です。Cコードをコンパイルするには、内部的なものが必要です。


4

ヘッダーファイルAが#includesヘッダーファイルBおよびCである場合、#includesAのすべてのソースファイルもBおよびCを取得し#includedます。プリプロセッサは、文字通りテキストの置換を実行します。ファイルを見つける#include <foo.h>と、foo.hファイルのテキストで置き換えるというテキストが見つかります。

#includesヘッダーとソースファイルのどちらを使用するかについては、さまざまな意見があります。個人的には、#includesデフォルトですべてをソースファイルに配置することを好みますが、他の前提条件のヘッダーなしにコンパイルできないヘッダーファイルは、#includeそれらのヘッダー自体にする必要があります。

また、すべてのヘッダーファイルにインクルードガードを含めて、複数回インクルードされるのを防ぐ必要があります。


4

一部の環境では、必要なヘッダーファイルのみが含まれていると、コンパイルが最も高速になります。他の環境では、すべてのソースファイルがヘッダーの同じプライマリコレクションを使用できる場合、コンパイルは最適化されます(一部のファイルには、共通のサブセットを超える追加のヘッダーがある場合があります)。理想的には、複数の#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などは、かなり煩わしいようです。


3

含まれているものだけを使用してビルドできるように、すべてのファイルを作成します。ヘッダーにインクルードが必要ない場合は削除してください。大きなプロジェクトでは、この規律を守らないと、そのファイルのコンシューマーが使用しているヘッダーファイルからインクルードを削除したときに、ビルド全体を壊すことになります。


1

ヘッダーに入れると、ソースファイルにincludeステートメントが含まれます。ただし、場合によっては、ソースファイルに配置する方が適切な場合があります。

他のソースにそのヘッダーを含めると、ヘッダーからインクルードも取得されることに注意してください。これは必ずしも望ましいことではありません。使用する場所のみを含める必要があります。


1

ヘッダーには、定数と関数宣言を宣言する必要があるファイルのみを含める必要があります。技術的には、これらのインクルードもソースファイルに含まれますが、明確にするために、実際に使用する必要があるファイルのみを各ファイルに含める必要があります。したがって、ヘッダー内のそれらを複数の包含から保護する必要もあります。

#ifndef NAME_OF_HEADER_H
#define NAME_OF_HEADER_H

...definition of header file...

#endif

これにより、ヘッダーが複数回含まれることがなくなり、コンパイラエラーが発生します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.