C で #includes を構造化する方法

foo.c 内に foo.h を含める必要があります。このようにして、foo.h を含む他の c ファイルが不必要に bar.h を保持することはありません。これは、ヘッダー ファイルを含めるための私のアドバイスです:

  • c ファイルにインクルード定義を追加します。これにより、コードを読むときにファイルの依存関係がより明確になります。
  • foo.h を foo_int.h と foo.h の 2 つのファイルに分割します。最初のものは、foo.c だけが必要とする型宣言と前方宣言を運びます。 foo.h には、外部モジュールに必要な関数と型が含まれています。これは、foo のプライベート セクションとパブリック セクションのようなものです。
  • 相互参照は避けてください。つまり、foo は bar を参照し、bar は foo を参照します。これはリンクの問題を引き起こす可能性があり、設計が悪いことの兆候でもあります

他の人が指摘したように、ヘッダー foo.h は、ソースファイル foo.c によって提供される機能を使用できるようにするために必要な情報を宣言する必要があります。これには、foo.c によって提供される型、列挙、および関数が含まれます。 (グローバル変数を使用しませんよね? 使用する場合は、それらも foo.h で宣言されます。)

ヘッダー foo.h は自己完結型で冪等でなければなりません。自己完結型とは、すべてのユーザーが foo.h をインクルードでき、他のどのヘッダーが必要になるかを心配する必要がないことを意味します (foo.h にそれらのヘッダーが含まれているため)。冪等性とは、ヘッダーが複数回含まれている場合、損傷がないことを意味します。これは、古典的な手法によって実現されます:

 #ifndef FOO_H_INCLUDED
 #define FOO_H_INCLUDED
 ...rest of the contents of foo.h...
 #endif /* FOO_H_INCLUDED */

質問:

ファイル foo.c には、foo.c のすべての宣言を含む foo.h が含まれています。 bar.c と bar.h も同様です。 foo.c 内の関数 foo1() は、bar.h で宣言され、bar.c で定義されている bar1() を呼び出します。ここで問題は、bar.h を foo.h 内に含めるか、または foo.c 内に含めるかです。

foo.h が提供するサービスが bar.h に依存しているかどうかによって異なります。 foo.h を使用する他のファイルが、foo.h の機能を使用するために、bar.h によって定義されたタイプまたは列挙型のいずれかを必要とする場合、foo.h は、bar.h が (それを含めることによって) 含まれていることを確認する必要があります。ただし、bar.h のサービスが foo.c でのみ使用され、foo.h を使用するユーザーに必要とされない場合、foo.h に bar.h を含めるべきではありません


ヘッダー ファイル自体に必要な *.h ファイルにヘッダー ファイルのみを含めます。私の意見では、ソース ファイルに必要なヘッダー ファイルはソース ファイルに含めて、依存関係がソースから明らかになるようにする必要があります。ヘッダー ファイルは複数のインクルードを処理できるように作成する必要があるため、明確にするために必要な場合は両方に含めることができます。