2008-11-09 27 views
6

假設我有一個C程序被分解爲一組* .c和* .h文件。如果一個文件中的代碼使用另一個文件中的函數,那麼我應該在哪裏包含頭文件?在使用該函數的* .c文件內部,還是在該文件的標題內部?如何構造#includes中的C

E.g.文件foo.c包括foo.h,其中包含foo.c的所有聲明;與bar.cbar.h相同。功能foo1()內部foo.c調用bar1(),它在bar.h中聲明並在bar.c中定義。現在的問題是,我應該在foo.h裏還是foo.c裏面包括bar.h

對於這些問題,什麼是一套很好的經驗法則?

回答

6

你應該在foo.c中包含foo.h。這樣,其他包含foo.h的c文件將不會不必要地攜帶bar.h。這是我對包含頭文件的建議:

  • 在c文件中添加包含定義 - 這樣讀取代碼時文件依賴關係更爲明顯。
  • 將foo.h分爲兩個單獨的文件,分別爲foo_int.h和foo.h。第一個包含僅由foo.c所需的類型和前向聲明。 foo.h包含外部模塊所需的功能和類型。這就像foo的私人和公共部分。
  • 避免交叉引用,即foo引用bar和bar引用foo。這可能會導致鏈接問題,也是不好的設計的跡象
+3

創建標頭的唯一原因是因爲多個源文件需要這些信息。在foo.h之外不應該需要foo_int.h頭文件,所以不應該創建或使用它 - 它的內容可以直接放在foo.c文件中。 – 2008-11-09 21:16:00

+0

繼續:當您有多個提供'foo.c'功能的源文件 - 比如說foo1.c和foo2.c時,您可以使用foo_int.h。那麼內部頭文件是有意義的。但是,您應該致力於保持足夠的緊湊性,以免C文件分割變得不必要。 – 2008-11-09 21:17:11

2

我在.h文件中包含最小的一組頭文件,其餘文件包含在.c文件中。這有時會縮短編譯時間。舉個例子,如果foo.h並不真的需要bar.h但包括它,並且其他一些文件包括foo.h,那麼如果bar.h更改,那麼該文件將被重新編譯,即使它實際上可能並不需要或使用bar.h

3

我只在頭文件本身需要的* .h文件中包含頭文件。在我看來,源文件所需的頭文件應該包含在源文件中,以便源文件中的依賴關係很明顯。頭文件應該被構建來處理多個包含,所以如果需要澄清,可以將它們放在兩個文件中。

2

.h文件應該定義公共接口(api)到.c文件中的函數。

如果文件1的接口使用文件2,然後#包括file2.h的file1.h

接口如果file1.c中的實施,使得在file2.c中使用的東西,然後在file1.c應#包括file2.h。

雖然我必須承認 - 因爲我總是在file1.c中包含file1.h - 我通常不會在file1.c中直接包含file2.h,如果它已經包含在file1.h中

如果您發現自己處於兩個.c文件包含其他.h文件的情況,那麼這表示模塊性已經崩潰,您應該考慮重構一些東西。

2

使用的foo.cfoo.h的例子中,我發現這些準則有所幫助:

  • 記住的foo.h的目的是爲了方便使用的foo.c,所以保持它的簡單,有組織,有自我儘可能地展現。解釋如何使用foo.c的功能 - 而當不是使用它們。

  • foo.h聲明的foo.c公共特性:函數,宏,類型定義,和(不寒而慄)全局變量。

  • foo.c應該#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本身所需的定義和聲明分開。但是,而不是創建兩個文件,它有時最好讓預處理器爲你做這個:

// 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 
4

正如其他人指出,一個頭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.h,它包含了所有的foo.c聲明; bar.c和bar.h也一樣。 foo.c中的函數foo1()調用bar1(),它在bar.h中聲明並在bar.c中定義。現在的問題是,我應該在foo.h中還是在foo.c中包含bar.h?

這取決於foo.h提供的服務是否依賴於bar.h。如果使用foo.h的其他文件需要bar.h定義的類型或枚舉之一以使用foo.h的功能,那麼foo.h應確保包含bar.h(通過包含它)。但是,如果bar.h的服務僅在foo.c中使用,並且使用foo.h的用戶不需要,則foo.h不應包含bar.h