Header C++ 中的守卫问题

Header Guarding questions in C++

刚开始自己​​写headers,但迫于需要,必须学习。

我正在写一个 header,我正在尝试理解 header 守卫。在包含的 header 文件前后有一个或两个下划线有区别吗?

举个假设的例子:x.h

//x.h
#ifndef __X_H_INCLUDED__
#define __X_H_INCLUDED__
//functions n stuff
#endif

对比:

//x.h
#ifndef _X_H_INCLUDED_
#define _X_H_INCLUDED_
//functions n stuff
#endif

一个比另一个更正确还是更不正确?有区别吗?

根据 C++11 17.6.4.3.2 Global names(尽管此限制已经存在一段时间):

Certain sets of names and function signatures are always reserved to the implementation:

  • Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
  • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

因此,如果您希望您的软件具有可移植性,那么您真的不应该使用 两者,话虽如此,很多人 使用两个品种。

使用GUARD_X_HX_H_INCLUDED之类的东西会“更安全”,当然,您仍然需要警惕冲突。您可能会采用 Java 方式并最终得到如下宏:

AU_COM_POWERFIELD_DATASTRUCTURES_TREES_BALANCED_BTREE_H

只要您不超过宏名称的实施限制(根据内存,至少为 1024 个字符)。

或者,如果您想牺牲可移植性(但不是很多可移植性,因为很多编译器都支持它),您可以查看 #pragma once,在那里您不必担心想出独特的名字。

来自 2003 C++ 标准(这些规则仍然适用):

17.4.3.2.1 Global names [lib.global.names]

Certain sets of names and function signatures are always reserved to the implementation:

Each name that contains a double underscore (_ _) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use. Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.165 165) Such names are also reserved in namespace ::std (17.4.3.1).

我喜欢遵循与项目结构相匹配的包含守卫的特定结构。

#ifndef PROJECT_PATH_TO_FILE_HPP
// etc. etc.

因此,如果项目名称为 "skittles",并且 header 的路径为 taste/the/rainbow.hpp,那么我的包含防护将变为:

#ifndef SKITTLES_TASTE_THE_RAINBOW_HPP
// etc. etc.

这很好用,您只需要注意名称与文件名和目录的冲突。例如,项目根目录中的一个文件名为 foo_bar.hpp,另一个文件位于 foo/bar.hpp。这将导致必须解决的名称冲突。

另一种选择是使用命名空间而不是路径:

#define PROJECT_NAMESPACE_MODULE_HPP

我还看到有人附加文件的创建日期和时间,或使用 UUID,以进一步防止名称冲突。