6

*.cファイルと*.hファイルのセットに分割されたCプログラムがあるとします。あるファイルのコードが別のファイルの関数を使用している場合、ヘッダーファイルをどこにインクルードする必要がありますか?関数を使用した*.cファイル内、またはそのファイルのヘッダー内?

たとえば、ファイルfoo.cには、 ;foo.hのすべての宣言を含むが含まれます。とについてもfoo.c同じです。で宣言され、で定義されている、呼び出し内の関数。さて、問題は、内部に含めるべきか、それとも内部に含めるべきかということです。bar.cbar.hfoo1()foo.cbar1()bar.hbar.cbar.hfoo.hfoo.c

そのような問題に対する経験則の良いセットは何でしょうか?

4

6 に答える 6

7

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

  • cファイルにインクルード定義を追加します。これにより、コードを読み取るときにファイルの依存関係がより明確になります。
  • foo.hを2つの別々のファイル、たとえばfoo_int.hとfoo.hに分割します。最初のものは、foo.cでのみ必要な型宣言と前方宣言を持っています。foo.hには、外部モジュールに必要な関数とタイプが含まれています。これは、fooのプライベートセクションとパブリックセクションのようなものです。
  • 相互参照、つまりfoo参照barとbar参照fooは避けてください。これはリンクの問題を引き起こす可能性があり、悪いデザインの兆候でもあります
于 2008-11-09T20:10:50.730 に答える
5

他の人が指摘したように、ヘッダー 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 を含めないでください。

于 2008-11-09T22:32:02.363 に答える
3

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

于 2008-11-09T20:03:28.000 に答える
3

の例を使用するfoo.cと、foo.h次のガイドラインが役立つことがわかりました。

  • foo.hの目的はの使用を容易にすることであることを忘れないでください。そのためfoo.c、可能な限り単純で、整理された、わかりやすいものにしてください。--の機能をいつ、どのように使用するか、またいつ使用しないかを説明するコメントを自由に付けてください。foo.c

  • foo.hfoo.c関数、マクロ、typedef、および (震える) グローバル変数の公開機能を宣言します。

  • foo.cshould #include "foo.h-- ディスカッションと、以下の Jonathan Leffler のコメントも参照してください。

  • foo.cコンパイルに追加のヘッダーが必要な場合は、それらを に含めますfoo.c

  • foo.hコンパイルに外部ヘッダーが必要な場合は、それらをfoo.h

  • プリプロセッサを活用して、foo.h複数回含まれないようにします。(下記参照。)

  • 何らかの理由で、別の.cファイルが の機能を使用するために外部ヘッダーが必要になる場合foo.cは、ヘッダーを に含めてfoo.h、次の開発者が不要なデバッグを行わないようにします。これを嫌う場合は、必要なヘッダーが含まれていない場合にコンパイル時に命令を表示するマクロを追加することを検討してください。

  • 非常に正当な理由がなく、明確に文書化されていない限り、.cファイルを別のファイルに含めないでください。.c

kgiannakakis が指摘したように、パブリック インターフェイスを、その内部でのみ必要な定義と宣言から分離すると便利foo.cです。ただし、2 つのファイルを作成するよりも、プリプロセッサにこれを行わせる方がよい場合があります。

// foo.c
#define _foo_c_         // Tell foo.h it's being included from foo.c
#include "foo.h"
. . .

 

// foo.h
#if !defined(_foo_h_)   // Prevent multiple inclusion
#define _foo_h_

// This section is used only internally to foo.c
#ifdef _foo_c_
. . .
#endif

// Public interface continues to end of file.

#endif // _foo_h_       // Last-ish line in foo.h
于 2008-11-09T22:21:55.380 に答える
2

可能な限り最小限のヘッダーのセットを.hファイルに含め、残りをファイルに含め.cます。これには、コンパイル時間を短縮できるという利点があります。あなたの例では、foo.h実際には必要ではないがbar.hとにかくそれを含み、他のファイルにが含まれている場合、実際にはを必要としない、または使用しない場合でも、変更がfoo.hあればそのファイルは再コンパイルされます。bar.hbar.h

于 2008-11-09T20:02:55.130 に答える
2

.h ファイルは、.c ファイル内の関数へのパブリック インターフェイス (別名 api) を定義する必要があります。

file1 のインターフェースが file2 のインターフェースを使用する場合、file1.h に file2.h を #include します。

file1.c の実装が file2.c のものを利用する場合、file1.c は file2.h を #include する必要があります。

ただし、私は常に file1.c に file1.h を #include するため、file2.h が file1.h に既に #include されている場合、file2.h を file1.c に直接 #include することは通常気にしません。

2 つの .c ファイルが互いの .h ファイルを #include する状況に陥ったことがある場合は、モジュール性が崩壊している兆候であり、物事を少し再構築することを検討する必要があります。

于 2008-11-09T20:27:51.477 に答える