ヘッダー(* .h)内でこのファイルで定義されたタイプが使用されている場合、#include
ファイルが必要ですか?
たとえば、GLibを使用しており、ヘッダーで定義された構造でgchar
基本型を使用する場合、*に既にあることを知って、#include <glib.h>
を実行する必要があります。 cファイル?
はいの場合は、#ifndef
と#define
の間、または#define
の後に挿入する必要がありますか?
NASAのゴダード宇宙飛行センター( [〜#〜] gsfc [〜#〜] )Cのヘッダーのルールは、ソースファイルにヘッダーを唯一のヘッダーとして含めることが可能である必要があることを示しています。そのヘッダーが提供する機能を使用するコードはコンパイルされます。
これは、ヘッダーが自己完結型でべき等的で最小限でなければならないことを意味します。
このルールの利点は、誰かがヘッダーを使用する必要がある場合、他のどのヘッダーも含める必要があるかを見つけるために苦労する必要がないことです。
考えられる欠点は、一部のヘッダーが何度も含まれることがあることです。これが、複数のインクルードヘッダーガードが重要である理由です(また、コンパイラーは可能な限りヘッダーを再インクルードしないようにしています)。
このルールは、ヘッダーが「FILE *
」や「size_t
」などのタイプを使用する場合、適切な他のヘッダー(<stdio.h>
または<stddef.h>
例)含まれる必要があります。忘れられがちな結果は、パッケージを使用するためにパッケージのユーザーが必要とするnotヘッダーをヘッダーに含めないことです。言い換えれば、ヘッダーは最小限でなければなりません。
さらに、GSFCルールは、これが起こることを確実にするための簡単な手法を提供します。
したがって、マジックソートがあるとします。
#ifndef MAGICSORT_H_INCLUDED
#define MAGICSORT_H_INCLUDED
#include <stddef.h>
typedef int (*Comparator)(const void *, const void *);
extern void magicsort(void *array, size_t number, size_t size, Comparator cmp);
#endif /* MAGICSORT_H_INCLUDED */
#include <magicsort.h>
void magicsort(void *array, size_t number, size_t size, Comparator cmp)
{
...body of sort...
}
ヘッダーには、size_t
を定義する標準ヘッダーを含める必要があることに注意してください。これを行う最小の標準ヘッダーは<stddef.h>
ですが、他のいくつかも同様です(<stdio.h>
、<stdlib.h>
、<string.h>
、場合によっては他のいくつか)。
また、前述したように、実装ファイルに他のヘッダーが必要な場合は、そうする必要があります。また、いくつかの余分なヘッダーが必要になることは完全に正常です。ただし、実装ファイル( 'magicsort.c')にはそれらを含める必要があり、ヘッダーを使用して含める必要はありません。ヘッダーには、ソフトウェアのユーザーが必要とするもののみを含める必要があります。実装者が必要とするものではありません。
コードで構成ヘッダー(GNU Autoconfおよび生成された「config.h」など)を使用している場合、「magicsort.c」でこれを使用する必要があります。
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "magicsort.h"
...
これは、モジュールのプライベートヘッダーが実装ファイルの最初のヘッダーではないことを知っている唯一の時間です。ただし、「config.h」の条件付きインクルードは、おそらく「magicsort.h」自体に含まれている必要があります。
上記のリンク先のURLは機能しなくなりました(404)。 C++標準(582-2003-004)は EverySpec.com ;にあります。 C標準(582-2000-005)は実際には欠落しているようです。
C標準のガイドラインは次のとおりです。
§2.1ユニット
(1)コードは、ユニットまたはスタンドアロンのヘッダーファイルとして構成されます。
(2)ユニットは、単一のヘッダーファイル(.h)と1つ以上の本体(.c)ファイルで構成されます。ヘッダーファイルと本文ファイルをまとめてソースファイルと呼びます。
(3)ユニットヘッダーファイルには、クライアントユニットが必要とするすべての関連情報が含まれます。ユニットのクライアントは、ユニットを使用するためにヘッダーファイルのみにアクセスする必要があります。
(4)ユニットヘッダーファイルには、ユニットヘッダーに必要な他のすべてのヘッダーの#includeステートメントが含まれます。これにより、クライアントは単一のヘッダーファイルを含めることでユニットを使用できます。
(5)ユニット本体ファイルには、他のすべての#includeステートメントの前に、ユニットヘッダーの#includeステートメントを含める必要があります。これにより、コンパイラは、必要なすべての#includeステートメントがヘッダーファイルにあることを確認できます。
(6)本体ファイルには、1つのユニットに関連付けられた機能のみが含まれます。 1つのボディファイルは、異なるヘッダーで宣言された関数の実装を提供しない場合があります。
(7)特定のユニットUの一部を使用するすべてのクライアントユニットには、ユニットUのヘッダーファイルが含まれます。これにより、ユニットUのエンティティが定義される場所は1つだけになります。クライアントユニットは、ユニットヘッダーで定義された関数のみを呼び出すことができます。本体で定義されているが、ヘッダーで宣言されていない関数を呼び出すことはできません。クライアントユニットは、本文では宣言されているがヘッダーでは宣言されていない変数にはアクセスできません。
componentには1つ以上のユニットが含まれます。たとえば、数学ライブラリは、ベクトル、行列、四元数などの複数のユニットを含むコンポーネントです。
スタンドアロンヘッダーファイルには、関連するボディがありません。たとえば、一般的なタイプのヘッダーは関数を宣言しないため、本文は必要ありません。
ユニットに複数のボディファイルがある理由:
- ボディコードの一部はハードウェアまたはオペレーティングシステムに依存していますが、残りは一般的です。
- ファイルが大きすぎます。
- このユニットは一般的なユーティリティパッケージであり、一部のプロジェクトでは一部の機能しか使用しません。各関数を個別のファイルに配置すると、リンカは最終イメージから使用されていない関数を除外できます。
§2.1.1ヘッダーには理論的根拠が含まれる
この標準では、ユニットのヘッダーに必要な他のすべてのヘッダーの
#include
ステートメントを含むユニットのヘッダーが必要です。ユニットヘッダーの#include
をユニット本体の最初に配置すると、コンパイラーはヘッダーに必要な#include
ステートメントがすべて含まれていることを確認できます。この規格で許可されていない代替設計では、ヘッダーに
#include
ステートメントを使用できません。すべての#include
sはbodyファイルで行われます。ユニットヘッダーファイルには、必要なヘッダーが適切な順序で含まれていることを確認する#ifdef
ステートメントが含まれている必要があります。代替設計の利点の1つは、本体ファイルの
#include
リストがmakefileで必要な依存関係リストとまったく同じであり、このリストがコンパイラーによってチェックされることです。標準設計では、ツールを使用して依存関係リストを生成する必要があります。ただし、ブランチが推奨する開発環境はすべて、このようなツールを提供しています。代替設計の主な欠点は、ユニットの必須ヘッダーリストが変更された場合、そのユニットを使用する各ファイルを編集して
#include
ステートメントリストを更新する必要があることです。また、コンパイラライブラリユニットに必要なヘッダーリストは、ターゲットによって異なる場合があります。代替設計のもう1つの欠点は、必要な
#ifdef
ステートメントを追加するために、コンパイラライブラリヘッダーファイルおよびその他のサードパーティファイルを変更する必要があることです。別の一般的な方法は、プロジェクトヘッダーファイルの前に、すべてのシステムヘッダーファイルを本文ファイルに含めることです。一部のプロジェクトヘッダーファイルは、システムヘッダーの定義を使用するため、またはシステム定義をオーバーライドするために、システムヘッダーファイルに依存する可能性があるため、この標準はこの慣行に従いません。このようなプロジェクトヘッダーファイルには、システムヘッダーの
#include
ステートメントが含まれている必要があります。ボディに最初に含まれている場合、コンパイラはこれをチェックしません。
情報 礼儀 Eric S. Bullington :
参照されているNASA Cコーディング標準は、インターネットアーカイブからアクセスおよびダウンロードできます。
質問はまた尋ねます:
はいの場合、
#include
と#ifndef
の間、または#define
の後に(#define
行)を挿入する必要もあります。
答えは正しいメカニズムを示しています—ネストされたインクルードなどは#define
の後にあるべきです(そして#define
はヘッダーの2番目の非コメント行でなければなりません)—しかし、それはなぜ説明しませんそのとおりです。
#include
と#ifndef
の間に#define
を配置するとどうなるかを考えてください。他のヘッダー自体に、おそらく間接的に#include "magicsort.h"
などのさまざまなヘッダーが含まれているとします。 magicsort.h
の2番目のインクルードが#define MAGICSORT_H_INCLUDED
の前に発生する場合、ヘッダーは、それが定義するタイプが定義される前に2回インクルードされます。そのため、C89およびC99では、typedef
型名が誤って再定義されます(C2011では同じ型に再定義できます)、andを取得しますファイルを複数回処理するオーバーヘッド。ヘッダーガードの目的をそもそも無効にします。これは、#define
が2行目であり、#endif
の直前に書き込まれない理由でもあります。与えられた式は信頼できます:
#ifndef HEADERGUARDMACRO
#define HEADERGUARDMACRO
...original content of header — other #include lines, etc...
#endif /* HEADERGUARDMACRO */
インクルードファイルで必要な場合にのみ、インクルードファイルに#includesを配置することをお勧めします。特定のインクルードファイルの定義が.cファイルでのみ使用される場合は、.cファイルにのみインクルードします。
あなたの場合、私は#ifdef /#endifの間のインクルードファイルにそれを含めます。
これにより、依存関係が最小限に抑えられるため、インクルードファイルが変更されても、インクルードを必要としないファイルを再コンパイルする必要がなくなります。
必要なインクルードファイルがこのインクルードの前に含まれていることを確認するために、次の構成を使用します。ソースファイルのみにすべてのヘッダーファイルを含めます。
#ifndef INCLUDE_FILE_H
#error "#include INCLUDE.h" must appear in source files before "#include THISFILE.h"
#endif
コンパイル中に、プリプロセッサは#includeディレクティブを指定されたファイルコンテンツに置き換えるだけです。無限ループを防ぐために使用する必要があります
#ifndef SOMEIDENTIFIER
#define SOMEIDENTIFIER
....header file body........
#endif
ファイルに含まれていた別のヘッダーにヘッダーが含まれていた場合、ファイルに再帰的に含まれるため、再度明示的に含める必要はありません。
はい、それは必要です。そうでない場合、コンパイラは「認識していない」コードをコンパイルしようとすると文句を言います。 #includeは、コンパイルを成功させるために宣言、構造などを取得するようコンパイラーに指示するヒント/ナッジ/エルボであると考えてください。 jldupontが指摘した#ifdef /#endifヘッダートリックは、コードのコンパイルを高速化することです。
ここに示すように、C++コンパイラがあり、プレーンCコードをコンパイルしているインスタンスで使用されます トリックの例を次に示します。
#ifndef __MY_HEADER_H __ #define __MY_HEADER_H __ #ifdef __cplusplus extern "C" { #endif /*構造体、宣言などのCコードはここに*/ #ifdef __cplusplus } # endif #endif/* __MY_HEADER_H__ */
現在、これが複数回含まれていた場合、コンパイラはシンボル__MY_HEADER_H__
が一度定義されると、コンパイル時間が短縮されます。 上記の例のシンボルcplusplusに注意してください。これは、Cコードが存在する場合にC++コンパイルに対処する通常の標準的な方法です。
これを示すために上記を含めました(ポスターの元の質問とは実際には関係ありませんが)。これがお役に立てば幸いです、よろしく、トム。
PS:C/C++の初心者には便利だと思っていたので、誰かにこれを投票させてすみません。コメント/批評などは大歓迎です。
ヘッダーからヘッダーを含める必要があります。cにヘッダーを含める必要はありません。インクルードは、不必要に複数回インクルードされないように、#defineの後に配置する必要があります。例えば:
/* myHeader.h */
#ifndef MY_HEADER_H
#define MY_HEADER_H
#include <glib.h>
struct S
{
gchar c;
};
#endif /* MY_HEADER_H */
そして
/* myCode.c */
#include "myHeader.h"
void myFunction()
{
struct S s;
/* really exciting code goes here */
}
通常、ライブラリ開発者は#ifndef /#define/#endif "trick"を使用して複数のインクルードからインクルードを保護するため、ユーザーはそれを行う必要がありません。
もちろん、チェックする必要があります...しかし、とにかくコンパイラーはある時点であなたに教えてくれます;-)それはコンパイルサイクルを遅くするので、とにかく複数のインクルードをチェックすることは良い習慣です。
プロジェクトの1つの共通ヘッダーファイルにすべての外部ヘッダーを含めるだけです。 global.hそしてすべてのcファイルにそれを含めます:
次のようになります。
#ifndef GLOBAL_GUARD
#define GLOBAL_GUARD
#include <glib.h>
/*...*/
typedef int YOUR_INT_TYPE;
typedef char YOUR_CHAR_TYPE;
/*...*/
#endif
このファイルは、インクルードガードを使用して、複数のインクルード、不正な複数の定義などを回避します。