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

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


当前回答

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

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

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

其他回答

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

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

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

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

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

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

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

首先包含与.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。

在C/ c++世界中,这是一个很难回答的问题,因为有太多超出标准的元素。

我认为头文件的顺序不是一个严重的问题,只要它编译,就像squelart说的。

我的想法是:如果所有这些标题中的符号没有冲突,任何顺序都是OK的,并且标题依赖问题可以在以后通过在有缺陷的.h中添加#include行来修复。

真正的麻烦出现在某些头文件根据上面的头文件改变其操作(通过检查#if条件)时。

例如,在VS2005的stddef.h中,有:

#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

现在的问题是:如果我有一个自定义头文件("custom.h"),需要与许多编译器一起使用,包括一些在系统头文件中不提供偏移量的旧编译器,我应该在我的头文件中写道:

#ifndef offsetof
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

并且一定要告诉用户在所有系统头文件之后#include "custom.h",否则,stddef.h中的offset行将断言一个宏重定义错误。

我们祈祷在我们的职业生涯中不再遇到这种情况。

要记住的一件重要的事情是,您的头文件不应该依赖于首先包含的其他头文件。确保这一点的一种方法是在任何其他头文件之前包含您的头文件。

《c++思维》特别提到了这一点,引用了Lakos的《大规模c++软件设计》:

可以通过确保组件的.h文件自己进行解析来避免潜在的使用错误——没有外部提供的声明或定义……将.h文件作为.c文件的第一行,可以确保.h文件中不缺少组件物理接口固有的关键信息(或者,如果有的话,在尝试编译.c文件时就会发现它)。

也就是说,按以下顺序包括:

这个实现的原型/接口头文件(即.h/。对应于.cpp/. Hh文件。cc文件)。 同一项目中的其他头文件,视需要而定。 来自其他非标准、非系统库(例如Qt、Eigen等)的头文件。 来自其他“几乎标准”库的头文件(例如,Boost) 标准c++头文件(例如iostream, functional等) 标准C头文件(例如,cstdint, direct .h等)

如果任何标题在这个顺序中有问题,要么修复它们(如果你的),要么就不要使用它们。抵制不编写干净头文件的库。

谷歌的c++风格指南几乎完全相反,没有任何正当理由;我个人倾向于Lakos方法。