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

tem*_*ame 0 c c-preprocessor ifndef

根据这个问题,似乎有一些灵活性可以写出 -

#ifndef _HEADER_H
Run Code Online (Sandbox Code Playgroud)

要么:

#ifndef __HEADER___H__
Run Code Online (Sandbox Code Playgroud)

它不是一成不变的.

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

#ifndef header.h
Run Code Online (Sandbox Code Playgroud)

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

5go*_*der 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. */
Run Code Online (Sandbox Code Playgroud)

你可以看到,如果你MY_HEADER_HI_REALLY_LIKE_BANANAS什么替代,这种机制同样有效.唯一的要求是它是一个有效的宏标识符,并且不与任何其他包含守卫的名称冲突.

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

#define MY_HEADER_H 1
Run Code Online (Sandbox Code Playgroud)

然后将宏定义为1.有些人这样做,但它并没有真正添加任何东西,价值1相当随意.我一般不这样做.唯一的好处是,如果你定义它1,你也可以使用#if#ifdef.

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

如果你说的话,预处理器找到正确头文件的逻辑

#include <myheader.h>
Run Code Online (Sandbox Code Playgroud)

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

  • @Aerovistae它不用于复制标题,它用于防止重复包含头文件.http://en.wikipedia.org/wiki/Include_guard对所发生的事情有一个公正的解释,以及为什么需要这些包括警卫. (2认同)