应该以什么顺序指定包含文件,即包含一个头文件在另一个头文件之前的原因是什么?

例如,系统文件、STL和Boost是在本地包含文件之前还是之后?


当前回答

首先包含与.cpp…换句话说,source1.cpp应该在包含任何其他内容之前包含source1.h。我能想到的唯一例外是在使用带有预编译头的MSVC时,在这种情况下,你被迫在其他任何东西之前包含stdafx.h。

理由:在任何其他文件之前包含source1.h可以确保它可以独立于它的依赖项。如果source1.h在以后有了依赖项,编译器会立即提醒您向source1.h添加所需的前向声明。这反过来又确保了头文件可以由它们的依赖项以任何顺序包含。

例子:

source1.h

class Class1 {
    Class2 c2;    // a dependency which has not been forward declared
};

source1.cpp

#include "source1.h"    // now compiler will alert you saying that Class2 is undefined
                    // so you can forward declare Class2 within source1.h
...

MSVC用户:我强烈建议使用预编译的头文件。因此,将标准头文件(以及其他永远不会改变的头文件)的所有#include指令移到stdafx.h。

其他回答

在决定特定的包含顺序时,需要合并几个单独的考虑事项。让我试着理清头绪。

1. 检查自制力

许多回答认为,include顺序应该作为头文件是否自包含的检查。这就混淆了测试和编译的考虑

您可以单独检查您的头文件是否自包含。“静态分析”是独立于任何编译过程的。例如,运行

gcc headerfile.h -fsyntax-only

测试头文件是否自包含可以很容易地编写脚本/自动化。甚至你的makefile也可以这样做。

无意冒犯,但Lakos的书是1996年的,把这些不同的问题放在一起听起来像90年代风格的编程。也就是说,有些生态系统(现在的Windows还是90年代的Windows ?)缺乏脚本/自动化测试的工具。

2. 可读性

另一个考虑因素是可读性。当您查找源文件时,您只想轻松地查看包含了哪些内容。因为你的个人品味和喜好是最重要的,尽管通常情况下你要么按照最具体到最不具体的顺序排列,要么相反(我更喜欢后者)。

在每个组中,我通常只是按字母顺序排列。

3.包含顺序重要吗?

如果头文件是自包含的,那么从技术上讲,包含顺序对编译结果应该没有任何影响。

也就是说,除非您对代码有特定的设计选择(有问题吗?),比如没有自动包含的必要宏定义。在这种情况下,您应该重新考虑您的程序设计,尽管它当然可能非常适合您。

给自己添砖加瓦。

每个头文件都需要是自给自足的,只有当它至少被首次包含一次时,才能对其进行测试 不应该通过引入符号(宏、类型等)来错误地修改第三方标头的含义。

所以我通常是这样的:

// myproject/src/example.cpp
#include "myproject/example.h"

#include <algorithm>
#include <set>
#include <vector>

#include <3rdparty/foo.h>
#include <3rdparty/bar.h>

#include "myproject/another.h"
#include "myproject/specific/bla.h"

#include "detail/impl.h"

每组之间用空行分隔:

第一个对应于此cpp文件的头(健全性检查) 系统头文件 第三方头文件,按依赖顺序组织 项目标题 项目私有头文件

还要注意,除了系统头文件外,每个文件都位于一个与其名称空间同名的文件夹中,因为这样更容易跟踪它们。

我很确定这在任何理智的世界里都不是一个推荐的实践,但我喜欢按文件名长度排列系统包含,在相同的长度内按词法排序。像这样:

#include <set>
#include <vector>
#include <algorithm>
#include <functional>

我认为在其他人之前包含自己的头文件是一个好主意,以避免包含顺序依赖的耻辱。

我不认为有一个推荐的顺序,只要它编译!令人恼火的是,有些头文件需要先包含其他头文件……这是头文件本身的问题,而不是包含顺序的问题。

我个人倾向于从局部到全局,每个小节按字母顺序排列,即:

H文件对应此CPP文件(如适用) 来自同一个组件的头文件, 来自其他组件的头文件, 系统头文件。

我的理由是1。它应该证明每个头文件(其中有cpp)可以在没有先决条件的情况下被#包含(terminus technicus:头文件是“自包含的”)。剩下的似乎就从这里顺理成章地展开了。

我建议:

正在构建的.cc模块的头文件。(有助于确保项目中的每个头文件对项目中的其他头文件没有隐式依赖。) C系统文件。 c++系统文件。 平台/操作系统/其他头文件(例如win32、gtk、openGL)。 项目中的其他头文件。

当然,在可能的情况下,每个部分都要按字母顺序排列。

总是使用前向声明来避免在头文件中包含不必要的#。