C 预处理器如何知道将HEADER_H转换为HEADER.H?

C 预处理器如何知道将HEADER_H转换为HEADER.H?,c,c-preprocessor,ifndef,C,C Preprocessor,Ifndef,每个人,似乎有一些灵活性,你可以写-- 或: #ifndef __HEADER___H__ 等等,它不是一成不变的 但我不明白为什么我们一开始就用下划线。为什么我不能写: #ifndef header.h 怎么了?为什么我们到处都放下划线,把所有东西都大写?预处理器如何处理下划线?因为#ifdef或#ifndef后面需要预处理器符号,而这些符号不能包含点 在(最新草案)规范(§6.10.1)中: 表单的预处理指令 #ifdef标识符新行组选项 #ifndef标识符新线组选项 检查标识符当前是

每个人,似乎有一些灵活性,你可以写--

或:

#ifndef __HEADER___H__
等等,它不是一成不变的

但我不明白为什么我们一开始就用下划线。为什么我不能写:

#ifndef header.h
怎么了?为什么我们到处都放下划线,把所有东西都大写?预处理器如何处理下划线?

因为
#ifdef
#ifndef
后面需要预处理器符号,而这些符号不能包含点

在(最新草案)规范(§6.10.1)中:

表单的预处理指令

#
ifdef标识符新行组选项

#
ifndef标识符新线组选项

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

标识符不能包含点(§6.4.2.1)

顺便说一句,不需要与文件名相关的
#ifdef
符号。您可以使用
\ifndef JESUISCHARLIEHEBDO

\ifndef I\u LOVE\u PINK\u ROSES\u而非黄色的预处理器指令保护头文件
foo.h
。但按照人类的习惯,这些名字往往是相互关联的。
请注意,以下划线开头的标识符是由实现定义的,因此您应该避免使用
\ifndef\u FOO\u INCLUDED
,而更喜欢使用
\ifndef FOO\u INCLUDED
头。h
不是有效的标识符。宏名称中不能有句点

也就是说,为include-guard宏选择的名称完全是任意的。毕竟,这只是另一个变量。以文件的名称命名它们纯粹是惯例(为了避免冲突也是合理的)

我鼓励您大声说出标题结构,看看预处理器做了什么

#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. */
如果用
I\u REALLY\u LIKE\u banana
或其他东西替换
MY\u HEADER\u H
,您会发现这种机制同样有效。唯一的要求是它必须是有效的宏标识符,并且不能与任何其他include-guard的名称冲突

在上面的示例中,宏定义为空。那很好,但这不是唯一的选择。第二行同样可以读懂

#define MY_HEADER_H 1
然后将宏定义为
1
。有些人这样做,但实际上没有添加任何内容,而且值
1
相当随意。我一般不这么做。唯一的优点是,如果将其定义为
1
,则除了
#ifdef
之外,还可以使用
#if

最后一点警告:以下划线开头或包含两个或更多连续下划线字符的标识符是为实现保留的,不应在用户代码中使用。因此,
\u MY_HEADER\u H
\u MY_HEADER\u H\u
都是不幸的选择

预处理器根据以下逻辑查找正确的头文件:

#include <myheader.h>
#包括

这完全无关。这里,
myheader.h
命名一个文件,预处理器将在多个目录中搜索它(通常可以通过
-I
命令行选项进行配置)。只有在找到并打开该文件后,它才会继续解析该文件,因此,它最终会找到include-guard,如果它以前已经解析过该文件,则会导致它实际上跳过该文件(因此已定义include-guard宏,因此第一次检查的结果为false).

当您尝试
#ifndef header.h
时会发生什么?第二部分的重点是:文件名和宏之间没有任何联系,只有在读者的头脑中。好的,但是如果系统没有关联,宏的值首先从哪里获得<代码>#ifndef头_H
…系统如何知道它是否已定义?宏的定义在哪里?在第二行。如果愿意,您可以将其定义为一个值,但空定义也可以。所以…(我是C新手)…是不是说您不会使用
#包含“header.h”
并使用
#ifndef
/
#define
复制该头?我试图弄清楚这两个文件应该如何相对使用,每种情况都是专门针对哪种情况的。@Aerovistae它不用于复制头文件,而是用于防止头文件重复包含。有一个公平的解释发生了什么,为什么这些包括警卫是必要的。
#include <myheader.h>