2015-01-07 162 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将是错误的。

请记住,在实际编译完成之前,预处理器会对它们进行评估,因此它们将在编译时进行评估。