2015-01-07 95 views
2

我有一個關於在C中包含警衛的問題。我已經做了一些閱讀,但會感謝一點澄清。C包括衛兵

假設我有一個帶有函數定義的頭文件「header.h」。

#ifndef HEADER_FILE 
#define HEADER_FILE 

int two(void){ 
return 2; 
} 

#endif 

此頭文件有一個包含保護。然而,我對#define HEADER_FILE實際上在做什麼感到困惑。假設我忘記了包含後衛,完全忽略添加'#define HEADER_FILE'對我來說完全合法。

所以我的問題:當我們定義HEADER_FILE時,我們究竟做了什麼?我們定義了什麼?爲什麼可以忘記包含guard,在這種情況下我們也可以忘記添加#define HEADER_FILE?

任何幫助表示讚賞!

+0

你可能不應該在頭文件中包含代碼,因爲include guard只防止多個包含是一個單獨的翻譯單元。在兩個單獨的源文件中包含該頭文件可能會在鏈接時導致雙重定義錯誤。 – paxdiablo

+0

嗯,代碼守衛內的非靜態函數定義。看起來像一個問題。 – chux

+1

這是真的,值得注意。代碼防護可以防止在單個事務中包含多個內容,但是當兩個不同的對象文件單獨編譯並隨後鏈接時,不會防止多重包含。在C中爲 –

回答

7

這是一個預處理宏。

所有這一切都爲預處理器的語法,這基本上說,如果宏尚未定義,定義,幷包括#ifndef#endif

什麼它實現阻止文件包含超過之間的所有代碼一次,其中可以導致您的代碼中的問題。

你的問題:

爲什麼它好就忘了包括在這種情況下,我們也可以忘記加入的#define HEADER_FILE後衛?

可以忘記它,因爲它仍然是合法的C代碼沒有它。預處理器在編譯之前先處理文件,如果沒有邏輯說明它爲什麼不應該在最終的程序中包含指定的代碼。這只是一種常見的做法,但並不是必需的。

一個簡單的例子可以幫助說明這是如何工作:

你的頭文件,header_file.h我們會說,這包含:

#ifndef HEADER_FILE 
#define HEADER_FILE 

int two(void){ 
    return 2; 
} 

#endif 

在另一個文件(foo.c),你可能有:

#include "header_file.h" 

void foo() { 
    int value = two(); 
    printf("foo value=%d\n", value);  
} 

一旦「預處理」並準備編譯,這將轉化爲:

int two(void){ 
    return 2; 
} 

void foo() { 
    int value = two(); 
    printf("foo value=%d\n", value);  
} 

所有的包括防護裝置完成這裏是確定是否將#ifndef ...#endif之間的標題內容應代替原來#include的粘貼。

但是,由於該函數未被聲明爲externstatic,並且實際上是在頭文件中實現的,所以如果您嘗試在另一個源文件中使用它,則會出現問題,因爲函數定義將不包含在內。

+0

所以如果我錯了,請糾正我。 HEADER_FILE基本上是一個「宏文件夾」,其中包含#ifndef和#endif之間所有內容的宏定義? – Izzo

+0

@Teague不,它只是一個符號,就像一個變量,但它只是預處理器語法。使用'#include'包含一個文件實際上只是將文件內容粘貼到另一個文件中的#include文件中。在這種情況下,預處理器會看到你之前已經定義了一個名爲'HEADER_FILE'的符號,並確定是否應該再次包含代碼 –

+0

你錯了 - thr預處理器發現HEADER_FILE已經被定義,因此跳過文件的其餘部分(它是一個很大的if語句) – pm100

1

您防止文件被包含不止一次,這裏

#ifndef HEADER_FILE 

你測試,如果HEADER_FILE沒有定義,如果這是真的,那麼

#define HEADER_FILE 

會,如果你定義它,現在將文件包含在另一個文件中,第一次它將定義HEADER_FILE,而第二次,它將被定義,因此該文件的內容不再被包括,因爲#ifndef HEADER_FILE將是錯誤的。

請記住,在實際編譯完成之前,預處理器會對它們進行評估,因此它們將在編譯時進行評估。