2010-02-07 70 views
23

我的基本知識C編譯過程最近已經生鏽了。我試圖找出以下問題的答案,但無法連接編譯,鏈接和預處理階段基礎知識。在Google上快速搜索也沒有多大幫助。所以,我決定來到最終的知識來源:) 頭文件中的變量定義

我知道:變量不應該在.h文件中定義。它可以宣佈他們在那裏。

原因:因爲頭文件可能包含在多個位置,因此重新定義變量多次(鏈接器給出錯誤)。

可能的解決方法:在頭文件中使用頭文件並在頭文件中定義變量。

它確實是一個解決方案:否。因爲標頭警衛是預處理階段。這是告訴編譯器,這部分已經包含在內,不再包含它。但是我們的多重定義錯誤來自鏈接器部分 - 在編譯之後。

這整件事讓我感到困惑,關於如何預處理&鏈接工作。我認爲預處理將不包括代碼,如果頭部防護符號已被定義。在那種情況下,不應該多變的問題的定義也得到解決?

這些預處理指令會將編譯過程從重新定義符號保護下的符號中保存,但鏈接器仍然獲取符號的多個定義?

回答

24

標題保護可以保護您免受單個源文件中的多個包含物的影響,而不是來自多個源文件。我想你的問題源於不理解這個概念。

這並不是說在處理這個問題的編譯期間,預處理器看守是保存的。實際上在編譯期間,只有一個源文件被編譯成一個obj,符號定義不會被解析。但是,如果鏈接器嘗試解析符號定義時進行鏈接,則會看到多個定義將其標記爲錯誤,從而導致混淆。

+0

yikes ...那其實很簡單:) – Methos 2010-02-07 15:47:53

10

您有兩個.c文件。他們分別編制。每一個都包含你的頭文件。一旦。每個人都有一個定義。他們在鏈接時發生衝突。

傳統的解決方案是:

#ifdef DEFINE_SOMETHING 
int something = 0; 
#endif 

然後你在只有一個 .c文件的#define DEFINE_SOMETHING。

+0

更好的解決方案是頭文件中的聲明和只有一個.c文件中的定義。 – 2010-02-07 17:03:26

+0

同意,但我認爲OP知道:-) – bmargulies 2010-02-07 17:48:22

24

有一兩件事,我已經在過去使用(當全局變量風靡一時):

var.h文件:

... 
#ifdef DEFINE_GLOBALS 
#define EXTERN 
#else 
#define EXTERN extern 
#endif 
EXTERN int global1; 
EXTERN int global2; 
... 
一個 .c文件

然後(通常是一個包含main()):

#define DEFINE_GLOBALS 
#include "var.h" 

其餘的源文件通常只包含「var.h」。

請注意,DEFINE_GLOBALS不是頭保護,而是允許根據是否定義來聲明/定義變量。這種技術允許聲明/定義的一個副本。

+0

-1:你沒有給出實際問題的答案... – 3lectrologos 2010-02-07 13:22:45

+11

嗯,真的。這只是一個很好的解決方案。 +1來彌補愚蠢的downvote。 – 2010-02-07 15:15:46

+0

@Richard:供參考,不打雙關:這是「流行」,不是「流行」。 – Multisync 2016-02-07 10:21:54

8

標頭防護裝置在同一翻譯單元(即,在相同的.c源文件中)中多次包括頭文件。如果您將文件包含在兩個或更多個翻譯單元中,則它們不起作用。

+0

是...你是對的。 – Methos 2010-02-07 15:48:53