包括头文件样式 - C ++

时间:2010-01-28 17:01:28

标签: c++ header-files

我有一个具有以下目录结构的项目。

root
--include
----module1
----module2
--src
----module1
----module2

因此foo.cpp中的文件src/module1必须包含类似

#include "../../include/module1/foo.hpp"

这看起来很乱,而且很难写。我发现写作包括像

#include <module1/foo.h>

并在编译看起来整洁时向root/include提供包含文件搜索路径。但是,我不确定这种风格有任何缺点。

您更喜欢哪一个?为什么?你也看到以上述方式组织文件有什么问题吗?

7 个答案:

答案 0 :(得分:4)

#include "../../include/module1/foo.hpp"

应尽可能避免指定路径。编译器为您提供了更清晰的替代方案。此外,干净的设计应该确保您不需要处理包含标题的相对路径。

更好地了解使用哪一个(包括使用引号还是尖括号) 可以从标准。

从我的C ++草案副本:

  

16.2源文件包含

     

2

形式的预处理指令
#include <h-char-sequence> new-line`
  

搜索序列   实现定义的地方   标题由唯一标识   <>之间的指定序列   分隔符,并导致替换   该指令的全部内容   标题的内容。怎么样的地方   指定或标识标题   是实现定义的。

     

3 A   表格的预处理指令

# include "q-char-sequence" new-line 
  

导致替换它   指令由整个内容组成   由...标识的源文件   指定序列之间的“   分隔符。   搜索指定的源文件   以实现定义的方式。   如果不支持此搜索,或者如果   搜索失败,指令是   重新处理就像读了

#include <h-char-sequence> new-line`
  

具有相同的包含序列   (包括&gt;字符,如果有的话)来自   原始指令。

     

7 虽然实现可能会提供制作机制   可用的任意源文件   &lt; &GT;搜索,一般程序员   应该使用&lt; &GT;标题的形式   提供实施,和   外部来源的“”形式   控制实施。

答案 1 :(得分:2)

我支持两种风格......用于不同的用途

假设您还有一个目录root/src/common用于我的示例

// in src/module1/foo.cpp
#include "module1/foo.h"

#include "../common/stringProcessing.h"

包含

我不想看到'include'目录,因为当然说找到确切的头文件更难...但是当你开始并向多个独立库移动时你需要抽象,因为你想要能够在不改变代码的情况下移动各种组件,而且我都是为了保持一致性。

此外,使用'..'总是存在风险,因为向后遍历的符号链接,它不会出现在你想到的地方:/

<强>来源

有时您的标头不公开,因此不在include目录中。这些通常用于与您的客户无关的实施细节。对于那些我使用..的人,如果需要,请准确确切地说明。

这允许: - 不要将-Isrc的所有可能目录混为一谈 - 轻松找到您的来源中的文件 - 轻松测试源之间的依赖关系(grep for ..

<强>其它

如果我必须输入

#include "module/foo.h"

然后我希望使用:

module::Foo myClass;

可以很容易地将一种特定类型与一个特定模块匹配。

需求一个库 - 一个名称相同的命名空间,可以很容易地导航我们工作中的大约300个或~400个组件:我们需要通过某种方式来组织它们!

这意味着您的初始布局会被重新设计为(对于module项目):

root
-- include
---- module
------ part1
------ part2
-- src
---- part1
---- part2

然后使用以下指令:-I/path../root/include 我希望您创建libmodule.so库或module二进制文件。

答案 2 :(得分:1)

我更喜欢第二种方式

#include <module1/foo.h>

我发现它使源更易于查看。问题是,当其他人来看你的代码时,它不一定是头文件所在的固有位置,而包含的第一种方式是。

答案 3 :(得分:1)

每种风格都有一些缺点,但我更喜欢你指定的风格。包含路径不得包含任何向上相关性(例如../..),并且必须指定它所依赖的模块。

答案 4 :(得分:1)

作为一个小改进,我建议您允许module1中的cc个文件直接访问他们的.h文件:

module1/%.cc: -I $ROOT/includes/module1

或类似的。这将在您的c文件中创建一个视觉效果,区分外部包含和默认包括:

// module1/abc.cc
#include <abc.h>
#include <module2/def.h>

答案 5 :(得分:1)

谷歌的C ++风格指南有一个section,他们讨论了包含的排序和命名。它基本上同意到目前为止在其他答案中所说的内容,但值得一看,因为它非常具体。

我更喜欢(并且Google同意)在include指令中没有使用..的相对路径。您初步评估它看起来整洁是正确的。拥有冗长,笨重的相对路径会使事情更难阅读,更难以重构。我认为你的方法是正确的。

至于将源文件和包含文件分成两个不同的子树:为什么不将源头文件放在源文件旁边?它使它们更容易匹配。除非你希望其他项目使用你的标题,只是链接到你的二进制文件,我想 &LT;耸肩/&GT;

答案 6 :(得分:1)

我不在#include指令中使用路径。根据我的经验,它们总是在维护阶段引起问题。许多编译器允许您为头文件指定搜索树。

文件可以移动

他们会的。您的层次结构将会改变您可能希望将文件放在不同的驱动器上。当其他用户修改您的代码时,他们可能会更改位置。当文件移植到另一个项目时,文件可能会移动。没有什么能阻止您的文件移动。

在不修改文件的情况下移动文件

知道文件将移动,如果路径在文件中,则移动文件时必须修改文件。如果没有文件中的路径,则只需要更改构建指令。对于大型项目,修改许多文件很麻烦(即使使用脚本)。

在我看来,#include指令中的路径是邪恶的。执行此操作的人员应接受再培训或发送给其他公司。