#ifndef FOO_H
#define FOO_H
// ...
#endif
然而,我认为这并不直观。如果没有看到文件名,很难知道
FOO_H
的用途和它的名称所指代的内容。什么被认为是最佳实践?
#ifndef FOO_H
#define FOO_H
// ...
#endif
FOO_H
的用途和它的名称所指代的内容。我个人遵循Boost的建议。它可能是最大的高质量C++库集合之一,而且它们没有问题。
建议如下:
<project>_<path_part1>_..._<path_partN>_<file>_<extension>_INCLUDED
// include/pet/project/file.hpp
#ifndef PET_PROJECT_FILE_HPP_INCLUDED
选择的宏名称应该:
_[A-Z]
开头或包含__
的都不合法)INCLUDED
结束另一个宏,那么可能会产生冲突)我已经了解GUID,但那些看起来很奇怪。
显然,我希望所有编译器都实现#pragma once
(或者更好的是,#pragma multiple
并且"once"是默认行为...)
根据我的经验,惯例是使用包含它们的头文件的名称来命名包含保护措施,但名称全部大写且句点用下划线代替。
因此,test.h
变成了 TEST_H
。
这种惯例在现实生活中的示例包括 Qt Creator,在自动生成类头文件时遵循此约定。
以下内容摘自Google代码风格指南:
所有头文件都应有 #define guards,以防止多次包含。符号名称应遵循 <PROJECT>_<PATH>_<FILE>_H_ 的格式。为确保唯一性,该格式应基于项目源树中的完整路径。例如,在名为 foo 的项目中,位于 foo/src/bar/baz.h 的文件应具有以下保护:
我在自己的项目中使用这种样式。
#ifndef FOO_BAR_BAZ_H_ #define FOO_BAR_BAZ_H_ ... #endif // FOO_BAR_BAZ_H_
CONFIG_H
(例如包含的库),那么使用 CONFIG_H_
就不会与其冲突。同样的原因,一些人使用前导下划线,但他们不应该这样做,因为那是保留的。 - RastaJedi#endif
指令之后使用注释作为头文件名称可以将其与其他常量区分开来。 - Kassi#include "mylib/myheader.h"
mylib/myheader.h
已经是一个独特的名称。只需将 / 和 . 替换为 _ 并大写即可。
#define MYLIB_MYHEADER_H
将FOO_H
替换为FOO_H_INCLUDED
,这样更清晰易懂。
正如其他人之前提到的,一个非常常见的约定是使用大写字母版本的名称,并将点替换为下划线:foo.h -> FOO_H。
然而,这可能会导致与简单和/或常见名称发生名称冲突。因此,在非空的Visual C++项目中,自动生成的头文件(例如stdafx.h)会附加一些随机字符串,例如:
#ifndef FOO_H__NsknZfLkajnTFBpHIhKS
#define FOO_H__NsknZfLkajnTFBpHIhKS
#endif
http://www.random.org/strings/ 是一个对于此类场景非常有用的随机生成器。
另外,如果文件是某个子模块的一部分,或者其内容驻留在一个特定的命名空间中,我也会将其添加到防护范围内:
#ifndef SOMECOMPONENT_FOO_H__NsknZfLkajnTFBpHIhKS
#define SOMECOMPONENT_FOO_H__NsknZfLkajnTFBpHIhKS
namespace somecomponent
{
...
}
#endif
我通常会查看现在的时间,并将其附加到字符串末尾,例如FOO_H_248
。这是一种额外的预防措施,你不需要记住它,所以不必担心它看起来很难懂。
我通常使用类似于FOO_H_INCLUDED_
的东西。一些(Microsoft)头文件具有非常类似GUID字符串表示形式的内容,但我从未需要过如此复杂的东西。
#ifdef blahblah...
,我几乎从来没有真正阅读正在检查的内容,它只是一个包含保护。 - David Rodríguez - dribeas