预处理器如何知道将HEADER_H转换为header.h?

时间:2015-01-13 19:43:14

标签: c c-preprocessor ifndef

根据this question,您似乎可以灵活地编写 - {/ p>

#ifndef _HEADER_H

或:

#ifndef __HEADER___H__

等。它不是一成不变的。

但我不明白为什么我们首先使用下划线。为什么我不能写:

#ifndef header.h

这有什么问题?为什么我们在任何地方放置下划线并将所有东西都资本化?预处理器用下划线做什么?

2 个答案:

答案 0 :(得分:5)

header.h不是有效的标识符。您不能在宏名称中有句号。

也就是说,您为包含保护宏选择的名称完全是任意的。毕竟,这只是另一个变量。在文件之后将它们命名为纯粹的约定(并且为了避免冲突是合理的)。

我鼓励你大声说出标题结构,看看预处理器的作用。

#ifndef MY_HEADER_H    /* If the macro MY_HEADER_H is not defined (yet)... */
#define MY_HEADER_H    /* ... then define it now ... */

...                    /* ... and deal with all this stuff ... */

#endif                 /* ... otherwise, skip all over it and go here. */

如果您将MY_HEADER_H替换为I_REALLY_LIKE_BANANAS或其他什么,您会发现此机制同样有效。唯一的要求是它是一个有效的宏标识符,并且不与任何其他包含守卫的名称冲突。

在上面的示例中,宏被定义为空。那没关系,但这不是唯一的选择。第二行同样可以阅读

#define MY_HEADER_H 1

然后将宏定义为1。有些人这样做,但它并没有真正添加任何内容,值1相当随意。我一般不这样做。唯一的好处是,如果您将其定义为1,除了#if之外,您还可以使用#ifdef

最后要注意的是:以下划线开头或包含两个或多个连续下划线字符的标识符是为实现保留的,不应在用户代码中使用。因此,_MY_HEADER_H__MY_HEADER__H__都是不幸的选择。

如果你说

,预处理器找到正确头文件的逻辑
#include <myheader.h>

完全不相关。这里,myheader.h命名一个文件,预处理器将在许多目录中搜索它(通常可以通过-I命令行选项配置)。只有之后它已经找到并打开文件它将继续解析它,从而最终会找到包含防护,如果它之前已经解析过,它将导致它基本上跳过文件(因此,已经定义了包含保护宏,因此第一次检查的结果为false。

答案 1 :(得分:1)

因为#ifdef#ifndef后面需要预处理程序符号,并且这些符号不能包含点。

C11(最新草稿)规范n1570(§6.10.1)中:

  

表格的预处理指令

     

# ifdef 标识符换行群组

     

# ifndef 标识符换行群组

     

检查标识符当前是否定义为宏名称。

和标识符不能包含点(第6.4.2.1节)

BTW,include guards不需要具有与文件名相关的#ifdef符号。如果您愿意,可以使用foo.h或由#ifndef JESUISCHARLIEHEBDO预处理程序指令保护头文件#ifndef I_LOVE_PINK_ROSES_BUT_NOT_YELLOW_ONES。但是通过 human 约定,名称通常是相关的。 请注意,以下划线开头的标识符是实现定义的,因此您应该避免#ifndef _FOO_INCLUDED但更喜欢#ifndef FOO_INCLUDED