根据这个问题,您如何编写它似乎有一些灵活性 -
#ifndef _HEADER_H
或者:
#ifndef __HEADER___H__
等等。它不是一成不变的。
但我不明白为什么我们一开始就使用下划线。为什么我不能只写:
#ifndef header.h
那有什么问题?为什么我们到处都下划线并且大写?预处理器对下划线做了什么?
根据这个问题,您如何编写它似乎有一些灵活性 -
#ifndef _HEADER_H
或者:
#ifndef __HEADER___H__
等等。它不是一成不变的。
但我不明白为什么我们一开始就使用下划线。为什么我不能只写:
#ifndef header.h
那有什么问题?为什么我们到处都下划线并且大写?预处理器对下划线做了什么?
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
命令行选项配置)。只有在它找到并打开文件之后,它才会继续解析它,因此,它最终会找到包含防护,如果它之前已经解析过文件,它将导致它基本上跳过文件(因此包含防护宏是已定义,因此第一次检查评估为假)。
因为#ifdef
or#ifndef
后面需要一个预处理器符号,而这些符号不能包含点。
表单的预处理指令
#
ifdef标识符换行组选择
#
ifndef标识符换行组选择检查标识符当前是否定义为宏名称。
并且标识符不能包含点(§6.4.2.1)
顺便说一句,包含警卫不需要具有#ifdef
与文件名相关的符号。如果需要,您可以使用或由预处理器指令foo.h
保护头文件。但按照人类惯例,这些名称通常是相关的。请注意,以下划线开头的标识符是实现定义的,因此您应该避免但更喜欢#ifndef JESUISCHARLIEHEBDO
#ifndef I_LOVE_PINK_ROSES_BUT_NOT_YELLOW_ONES
#ifndef _FOO_INCLUDED
#ifndef FOO_INCLUDED