C ++标头保护语法

时间:2016-11-10 23:24:35

标签: c++ c++11 c-preprocessor c++14

对于文件名a.h ...我一直使用

#ifndef A_H
#define A_H
#endif

但现在我在教程

中看到了
#ifndef __A_H_INCLUDED__ 
#define __A_H_INCLUDED__ 
#endif

以及

#ifndef _A_H_INCLUDED 
#define _A_H_INCLUDED
#endif

所以我想知道发生了什么......从来没有版本的C ++发生了变化,还是这个编译器依赖?

我使用MinGw(gnu gcc g ++)和msvc ...

修改

如果对于为什么要问这个问题感到困惑,我相信这对初学者来说很困惑。例如,对于名为a.h的文件,我们不说

#ifndef a.h
#define a.h

甚至

#ifndef A_H
#define A_H a.h

这对我有意义。

相反,我们说A_H ......或上面的变体之一。因此,我认为不只是任何语法都可以。我总是认为它必须是大写字母的文件名,并且句号必须用_替换。这就是我多年来一直在教它的方式。不,我看到像_INCLUDED这样的单词......这些单词显然不是a.h文件名的一部分......这很令人困惑......编译器如何协调 A_H_INCLUDED 是指a.h?我不明白为什么这会被投票,我认为这很令人困惑。

此外,有人指出其中一些变体不符合标准,因此我认为这是一个有效的问题,不应该被投票。

或者#define A_H是否将头文件中的所有代码转储到A_H宏中?但我认为定义以新行字符结束......在这种情况下,我们定义A_H没有值。在这种情况下,A_H只是一个没有价值的名称,问题仍然是当你使用像 A_H_DINGDONG 那样的时髦空marco变量时编译器如何知道你正在谈论文件a.h?

5 个答案:

答案 0 :(得分:1)

#ifndef#define#endif是重要的语法部分。您使用的命名约定取决于您。

答案 1 :(得分:1)

这些只是变量名等名称。

保留双下划线名称,严格来说#define __A_H_INCLUDED__是未定义的行为,下划线+大写字母shouldn't be used either

您只是想避免命名与其他代码和标准的冲突,并且使用文件名通常可以确保。

答案 2 :(得分:1)

语言没有相关变化。包含保护中使用的标识符只是一个标识符。实际上整个包含保护机制并不是由语言定义的;它只是一个惯例。

问题是,以两个下划线或一个下划线和大写字母开头的标识符将保留给实现。这意味着如果您在代码中使用名称__FOO_H__,那么编译器已经为其内部目的预先定义了它,并且您的代码可能会以某种不确定的方式中断。

告诉你写的教程:

#ifndef __A_H_INCLUDED__ 
#define __A_H_INCLUDED__ 
#endif

给你很差的建议。

还有一个细微之处:以E开头的宏名称和一个数字,或E和一个大写字母,保留在<errno.h> / <cerror>标题中使用。因此,如果您的头文件被称为earth.h并且您写了:

#ifndef EARTH_H
#define EARTH_H
#endif

然后您原则上EARTH_H错误号冲突。

这不太可能发生,_H后缀几乎肯定足以阻止它,但我用来完全避免它的惯例是:

#ifndef H_EARTH
#define H_EARTH
#endif

你建议:

#define a.h

宏名称必须是单个标识符。这实际上定义了值为a的宏.h

#define A_H a.h

由于宏仅使用#ifndef进行测试,因此它的价值并不重要,只是它是否已定义。

答案 3 :(得分:0)

归结为个人/组织偏好,尽管有一些约定。一般来说,只要它没有在其他任何地方使用,它并不重要。

一些例子:

  • A_H:看起来类似于您在代码中使用的常量。
  • A_H_:会更好,因为你不可能在最后看到一个带有下划线的常量。
  • _A_H_INCLUDED:乍一看,这个看起来更好,因为它在外观上与私有文件范围变量相似。 这是一个问题,因为下划线+大写字母是保留的,所以这不是一个合适的宏。
  • A_H_INCLUDED:没有领先的下划线,明确的目的,不会与您计划中的任何其他内容发生冲突。
  • __A_H_INCLUDED__:保留双下划线;不要使用。

此外,它不是标准的一部分,但#PRAGMA ONCE得到广泛支持并完成同样的事情而无需担心命名约定。

答案 4 :(得分:0)

#define A_H

与文件a.h没有任何关联。

dir/filename.h内,你可以:

#ifndef WHATEVER_NOT_DEFINED_HENCE_HAVE_DIR_FILENAME_H_IS_GOOD_
#define WHATEVER_NOT_DEFINED_HENCE_HAVE_DIR_FILENAME_H_IS_GOOD_
#endif

但您无法使用此

#define WHATEVER_HAS_DOUBLE_UNDERSCORE_LIKE_THIS_IS_BAD__
#define __OR_LIKE_THIS_IS_BAD
#define OR_LIKE__THIS_IS_BAD

并且你不能以下划线开头,然后跟这样的大写字符:

#define _LIKE_THIS_IS_BAD