我知道这对项目没有什么影响,但是,假设您对 C++ 代码使用#defined 标头保护,您使用什么格式?例如假设一个名为foo.hpp
:
#ifndef __FOO_HPP__
...
#ifndef INCLUDED_FOO_HPP
...
#ifndef SOME_OTHER_FORMAT
我对大写#defines 的想法很满意,但无法确定这些守卫的格式。
我知道这对项目没有什么影响,但是,假设您对 C++ 代码使用#defined 标头保护,您使用什么格式?例如假设一个名为foo.hpp
:
#ifndef __FOO_HPP__
...
#ifndef INCLUDED_FOO_HPP
...
#ifndef SOME_OTHER_FORMAT
我对大写#defines 的想法很满意,但无法确定这些守卫的格式。
我总是在包含保护中包含命名空间或相对路径,因为只有标头名称已被证明是危险的。
例如,您有一些大型项目,代码中的某处有这两个文件
/myproject/module1/misc.h
/myproject/module2/misc.h
因此,如果您为包含保护使用一致的命名模式,您最终可能会_MISC_HPP__
在两个文件中都定义(发现这样的错误非常有趣)。
所以我解决了
MYPROJECT_MODULE1_MISC_H_
MYPROJECT_MODULE2_MISC_H_
这些名字比较长,但比起双重定义的痛苦,还是值得的。
另一种选择,如果您不需要编译器/平台独立性,您可能会寻找一些 #pragma once 的东西。
我总是用INCLUDED_FOO_HPP
我不会使用双下划线,因为以双下划线开头的东西是保留的。
为了真正避免名称冲突,我使用 GUID:
#ifndef GUARD_8D419A5B_4AC2_4C34_B16E_2E5199F262ED
就个人而言,我只使用文件名 FOO_HPP。Google 使用 SRC_ENGINE_FAST_HPP 之类的整个路径。
某些名称和函数签名集始终保留给实现:
- 每个包含双下划线 (_ _) 或以下划线后跟大写字母 (2.11) 的名称都保留给实现以供任何使用。
- 每个以下划线开头的名称都保留给实现用作全局名称空间中的名称。
( 17.4.3.1.2/1
)
我更喜欢这种格式:
#ifndef FOO_HPP
#define FOO_HPP
/* ... */
#endif // FOO_HPP
MYLIB_FOO_HPP
,它有助于避免命名冲突。我用
#if !defined(FOO_HPP_INCLUDED)
我更喜欢现代defined
语法,因为它允许 || && 运算符,即使这里没有使用它们。
还
#ifndef __FOO_HPP__
在技术上是非法的,因为前导下划线是保留的。
如果您使用 Visual Studio 或 Microsoft 编译器,请使用 pragma 方式
#pragma once
我总是使用
#ifndef FOOBAR_CPP
我也一直使用类似的东西:
#ifndef FOO_HPP
#define FOO_HPP 1
...
#endif
正如大多数人所提到的,不要在符号前面加上双下划线,因为这是 C++ 标准保留的,供实现内部使用。
您可能想查看 John Lakos 的优秀书籍“Large Scale C++ Software Design”(亚马逊链接- 为脚本 Kiddy 链接纳粹清理),以了解有关标头包含的一些注意事项。
高温高压
干杯,
抢
当我的时间得到报酬并且还没有公司标准时,我使用:
#ifndef path_to_file_h
#define path_to_file_h
小写的原因是更容易复制和粘贴文件名,并用下划线替换斜线。#ifndef 的原因是它与#define 很好地对齐,从而更容易看到符号相同。不过,我喜欢 GUID 的想法,所以我可能会尝试一下。
当我没有为我的时间付费,也没有将我的代码发布到野外时,我只使用#pragma once
. 与大多数其他可移植性问题不同,稍后添加包含防护与现在一样容易,并且可以由对代码库一无所知的人完成(例如,一年后的我,或者我将代码发送给某个无辜的程序员) ,所以 YAGNI 适用。
我倾向于使用:
#ifndef FILE_DATE_H_
(将 _H_ 替换为适当的扩展名,如 _HPP_ 等)。日期戳是为了避免与其他方向/库中的其他同名标题发生冲突。
所以最后它看起来像这样:
#ifndef SOMEFILE_20082411_H_
我用
<FILENAME_IN_ALL_CAPS>_<YYYYMMDD>
或者
<FILENAME_IN_ALL_CAPS>_INCLUDED_<YYYYMMDD>
与文件夹层次结构保持同步太烦人了(重构的朋友),GUID 太烦人了,日期后缀就足够了。如果我必须在同一天同样命名文件,我会
<FILENAME_IN_ALL_CAPS>_<YYYYMMDD>a
<FILENAME_IN_ALL_CAPS>_<YYYYMMDD>b
<FILENAME_IN_ALL_CAPS>_<YYYYMMDD>...
我会选择文件路径 + 升压_INCLUDED
后缀加上现在广泛支持的#pragma once
在很多编辑器中(对我来说它是崇高的),您还可以为此定义一些宏/片段。
这是为您做的一个:
<snippet>
<content><![CDATA[
#ifndef ${1:${TM_FILEPATH/(.*\/(include|src))*([^a-zA-Z0-9_]+)*([a-zA-Z0-9_]+)([.])*([a-zA-Z0-9_]+)*/\U$4_$6/ig}_INCLUDED}
#define $1
#pragma once
$0
#endif // $1
]]></content>
<tabTrigger>incguard</tabTrigger>
<description>include guard</description>
</snippet>
所以yourproject/include/yourlib/yourfile.hpp
变成YOURLIB_YOURFILE_HPP_INCLUDED
一个额外的外部源代码样式检查器工具可以通过这种方式轻松跟踪您的警卫的一致性。