为啥在 C++ 头文件中使用 #ifndef 和 #define?

Posted

技术标签:

【中文标题】为啥在 C++ 头文件中使用 #ifndef 和 #define?【英文标题】:Why are #ifndef and #define used in C++ header files?为什么在 C++ 头文件中使用 #ifndef 和 #define? 【发布时间】:2010-12-11 20:33:14 【问题描述】:

我经常在头文件的开头看到这样的代码:

#ifndef HEADERFILE_H
#define HEADERFILE_H

文件末尾是

#endif

这样做的目的是什么?

【问题讨论】:

+1 - 我也有同样的疑问,在这里得到了更好的答案,可能对未来的访问者有用:***.com/q/3246803/1134940 我想补充一点,你也可以使用#pragma once,这就是你所要做的,它的作用与ifndef相同。两者对比见:***.com/questions/1143936/… 最好提一下#pragma 是什么:它激活了特定于编译器的功能。尽管#pragma once 得到了非常广泛的支持,但它是非标准的。 @Dimension: GNU 自己的文档(info cpp 或look here)说“它不是所有预处理器都能识别的,所以你不能在可移植程序中依赖它。”。并且 GNU cpp 优化了通用和可移植的 #ifndef 习惯用法,因此它与 #pragma once 一样高效。 一些需要考虑的事情: 不要使用以下划线开头的宏名称;此类标识符保留给实现。更巧妙的是,#ifndef HEADERFILE_H 可以违反实现的命名空间,标题名称恰好以E 开头;以E 和数字或大写字母开头的标识符保留给<errno.h>。我建议#ifndef H_HEADERFILE 【参考方案1】:

那些被称为#include guards。

一旦包含标头,它会检查是否定义了唯一值(在本例中为 HEADERFILE_H)。然后,如果它没有定义,它会定义它并继续到页面的其余部分。

当再次包含代码时,第一个ifndef失败,导致一个空白文件。

这可以防止重复声明任何标识符,例如类型、枚举和静态变量。

【讨论】:

Koning Baard XIV: VC 甚至有一个 #pragma once 也是如此:-) 它还可以防止递归包含...想象一下“alice.h”包含“bob.h”而“bob.h”包含“alice.h”并且它们没有包含保护。 . @Kevin:这就是我的意思。我想操作一个由要操作的表单打开的表单。它给了我很多错误,我不知道该怎么办。我放弃了=) @Јοеу: #pragma once 不可移植;推荐使用常见的#ifndef 成语。 @CIsForCookies 将“一个定义规则”打入您最喜欢的搜索引擎。【参考方案2】:
#ifndef <token>
/* code */
#else
/* code to include if the token is defined */
#endif

#ifndef 检查给定的令牌是否在文件或包含文件的前面是#defined;如果没有,它包括它和结束 #else 之间的代码,或者,如果不存在 #else,则包含 #endif 语句。 #ifndef 通常用于使头文件具有幂等性,方法是在包含文件后定义一个标记并检查该标记是否未设置在该文件的顶部。

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

【讨论】:

保留以下划线开头的标识符;你不应该自己定义它们。使用 #ifndef H_HEADER_NAME 之类的东西。 我知道这是一个旧评论,但实际上下划线限制仅适用于“外部标识符” - 可能最终出现在编译对象的符号表中的标识符,即全局变量和函数名。它不适用于宏名称。 斯图的评论是真的吗?我刚刚读了***.com/questions/228783/…,现在我不太确定。 不,尽管这是一种常见的做法,但用户在 C++ 的任何范围内定义以下划线开头的任何符号后跟大写字母都是未定义的行为。在实践中,此类符号可用于定义标准库中的宏,这可能与用户定义的相同形式的符号发生冲突(我期待 2023 年的回应;问候,从鼠疫时代开始!)例外:用户定义的文字。【参考方案3】:

这样可以防止多次包含同一个头文件。

#ifndef __COMMON_H__
#define __COMMON_H__
//header file content
#endif

假设您已将此头文件包含在多个文件中。所以第一次 __COMMON_H__ 未定义,它将被定义并包含头文件。

下一次定义__COMMON_H__,所以它不会再次包含。

【讨论】:

【参考方案4】:

它们被称为 ifdef 或包含守卫。

如果编写一个小程序,似乎不需要它,但随着项目的发展,您可能会有意或无意地多次包含一个文件,这可能会导致编译警告,如变量已声明。

#ifndef checks whether HEADERFILE_H is not declared.
#define will declare HEADERFILE_H once #ifndef generates true.
#endif is to know the scope of #ifndef i.e end of #ifndef

如果没有声明,这意味着#ifndef 生成true,那么只有#ifndef 和#endif 之间的部分执行,否则不执行。这将防止再次声明标识符、枚举、结构等...

【讨论】:

以上是关于为啥在 C++ 头文件中使用 #ifndef 和 #define?的主要内容,如果未能解决你的问题,请参考以下文章

有 C++ 标准库 ifdef 或 ifndef 预处理器指令吗?

C++中 语句 #ifndef

为啥我们需要在 C++ 头文件中使用“#if defined Identifier”?

C++两个头文件相互包含

C++进阶之路C++防止头文件被重复引入的3种方法!

关于头文件