对于头文件来说,“ . ./include/header.h”这样的相对路径有什么好处?

我已经回顾了问题 如何正确使用头文件C + + # 包含语义,没有解决这个问题,也没有其他建议的索时,我打字的标题..。

如果有的话,写作的好处是什么:

#include "../include/someheader.h"
#include "../otherdir/another.h"

与只使用普通文件名相比:

#include "someheader.h"
#include "another.h"

或者可能是一个没有“ ..”的亲属名称:

#include "include/someheader.h"
#include "otherdir/another.h"

我看到的问题是:

  • 如果不考虑哪些源文件包含标头,就无法移动标头。
  • 在依赖项和错误报告中,头的路径可能非常长。我今天和“ ../dir1/include/../../include/../dir2/../include/header.h”有一个。

我能看到的唯一优点是,虽然您不需要移动文件,但是您可能不需要总是使用“ -I”指令来查找头文件,但是灵活性的损失,以及在子目录中编译的复杂性等似乎超过了好处。

我是不是忽略了一个好处?


谢谢你的建议。我认为大家的共识是,使用这种符号没有任何重大好处”。."被我忽略了。一般来说,我喜欢“ where/header.h”符号; 我确实在新项目中使用它。我正在研究的这个绝对不是新的。

其中一个问题是有各种各样的头,通常带有前缀,如 rspqr.hrsabc.hrsdef.hrsxyz.h。这些都与 rsmp目录中的代码有关,但是一些头在 rsmp中,另一些头在中央包含目录中,该目录中没有诸如 rsmp这样的子目录。(对代码的其他各个区域重复执行; 有多个位置的头,其他位代码随机需要这些头。)移动东西是一个主要问题,因为这些年来代码变得非常复杂。而且在提供 -I选项的情况下,makefile 并不一致。总而言之,这是一个几十年来不那么善意的忽视的悲惨故事。在不打破任何东西的情况下修复这一切将是一项漫长而乏味的工作。

93546 次浏览

因为这样您就可以将文件放置在相对于项目根目录的位置,并且当您将文件签入到源代码管理中时,另一个开发人员将其签出到其本地系统上的不同位置时,文件仍然可以工作。

我更喜欢路径语法,因为它非常清楚地表明头文件属于哪个名称空间或模块。

#include "Physics/Solver.h"

非常自我描述,而不需要每个模块的名称前缀头文件。

不过,我几乎从不使用“ . .”语法,而是让我的项目包含指定正确的基本位置。

将源树想象成一个嵌套的名称空间,include 路径允许您将目录拉到这个名称空间的根目录中。那么问题就是不管代码在磁盘上是如何组织的,都要为代码库形成一个逻辑名称空间。

我会避免这样的路径:

  • "include/foo/bar.h"ーー“包含”似乎是不合逻辑和多余的
  • “ . .”假定相对位置,是脆弱的
  • 除非 bar.h 在工作目录中,否则这会污染全局名称空间,并导致含糊不清。

就个人而言,我倾向于在我的项目包括路径ーー "..;../..;../../..;../../../.."中添加以下路径。

这允许您对 #include应用一种隐藏规则,并允许在不破坏其他代码的情况下移动标题的一些自由。当然,如果不注意非完全限定名称可能(或者随着时间的推移)不明确,这样做的代价是引入绑定到错误头文件的风险。

我倾向于在公共头中完全限定 #include,这样任何使用我的代码的第三方都不需要将 "..;../..;../../..;../../../.."添加到他们的项目中ーー这只是为我的私有代码和构建系统提供了方便。

IANALL,但是我不认为你应该把 ..放在实际的 C 或 C + + 源文件中,因为那是不可移植的,而且标准也不支持它。这类似于在 Windows 上使用 \。只有在编译器无法使用任何其他方法时才这样做。

#include "../include/header.h"的问题在于,它经常会意外地工作,然后一个看似不相关的更改会使它以后停止工作。

例如,考虑下面的源布局:

./include/header.h
./lib/library.c
./lib/feature/feature.c

假设你运行的编译器的包含路径是 -I. -I./lib,会发生什么?

  • ./lib/library.c可以做 #include "../include/header.h",这是有道理的。
  • ./lib/feature/feature.c也可以做 #include "../include/header.h",即使它没有意义。这是因为编译器将尝试相对于当前文件位置的 #include指令,如果失败,它将尝试相对于 #include路径中的每个 -I条目的 #include指令。

此外,如果您稍后从 #include路径中删除 -I./lib,那么您将中断 ./lib/feature/feature.c

我觉得下面这些更好:

./projectname/include/header.h
./projectname/lib/library.c
./projectname/lib/feature/feature.c

我不会添加除 -I.以外的任何包含路径条目,那么 library.cfeature.c都将使用 #include "projectname/include/header.h"。假设“ projectname”可能是唯一的,那么在大多数情况下,这不应该导致名称冲突或歧义。如果绝对必要的话,您还可以使用 include path 和/或 make 的 VPATH特性将项目的物理布局划分到多个目录中(例如,为了适应特定于平台的自动生成代码; 当您使用 #include "../../somefile.h"时,这个特性会真正崩溃)。

具有相对路径的窗口的另一个问题是 MAX _ PATH。这将触发编译问题时,例如交叉编译为 android 和您的路径增长超过260的长度。

以一个或多个“ ../”序列开始 #include ""指令的路径:

  • 您希望包含与包含文件并置的文件是固定的,并且
  • 您正在构建一个 POSIX 系统或使用 VC + + 和
  • 您希望避免包含哪个文件的模糊性。

总是很容易提供一个示例,说明您的代码库在何处包含错误,以及这种错误随后会在何处导致难以诊断的故障。但是,即使您的项目是无错的,如果您依赖于绝对路径来指定相对于另一个文件位置的文件,它也可能被第三方滥用。

例如,考虑以下项目布局:

./your_lib/include/foo/header1.h
./your_lib/include/bar/header2.h
./their_lib/include/bar/header2.h

Your _ lib/include/foo/header1.h应该如何包含 Your _ lib/include/bar/header2.h? 让我们考虑两种选择:

  1. #include <bar/header2.h>

    假设同时引用 Your _ lib/includeTheir _ lib/include作为头搜索路径(例如使用 GCC 的 -I-isystem选项) ,那么选择哪个 标题2.h将被选择对这两个路径的搜索顺序敏感。

  2. #include "../bar/header2.h"

    编译器将搜索的第一个位置是 Your _ lib/include/foo/header1.h的位置,即 Your _ lib/include/foo/。它将首先尝试 Your _ lib/include/foo/. ./bar/header2.h减少到 Your _ lib/include/bar/header2.h,在那里它将找到正确的文件。头搜索路径将根本不会被使用,并且几乎没有歧义的空间。

我强烈建议选项2)在这种情况下给出的理由。

针对其他答案中的一些论点:

  • @ 安德鲁-格兰特 :

    ... 它清楚地表明头文件属于哪个名称空间或模块。

    也许吧。但是相对路径可以解释为“在同一个模块中”。在不同模块中有多个具有相同名称的目录的情况下,它们提供了明确性。

  • @ bk1e :

    它经常会意外地发挥作用。

    我认为,相对路径只有在项目从一开始就中断并且很容易修复的极少数情况下才会偶然发挥作用。在不引起编译器错误的情况下经历这样的名称冲突似乎是不太可能的。一个常见的场景是,依赖项目的文件包含您的一个头文件,其中又包含另一个头文件。编译您的测试套件应该会导致“没有这样的文件或目录”错误时,编译独立于该依赖项目。

  • @ singlenegationdelete@a href = “ https://stackoverflow. com/a/597414/671509”> 说

    不便携,标准也不支持。

    ISO C 标准不能指定编译或运行程序的系统的所有细节。这并不意味着它们不受支持,只是标准没有过度指定 C 将在哪些平台上运行。(在 POSIX 标准中,公共现代系统 可能来源于上如何解释 ""<>之间的区别。)

  • @ daniel-paull@a href = “ https://stackoverflow. com/a/597393/671509”

    “ . .”假定相对位置,是脆弱的

    怎么个脆弱法?可能对这两个文件的搭配很敏感。因此,“ ..”应该只(并且始终)在包含文件的作者控制其位置时使用。

抛出另一个绝对参数(或“扩展相对”)包括路径,如 #include "./lib/subdir/~/subsubsubsubdir/header.h"... 当工作在一个真正的大型项目,一个可能需要 很多"-I./~"选项的链接线。在我当前的一个项目中,这些选项占用的字符数接近40k,由于命令行限制而导致错误。

虽然通常我不喜欢那种包含路径的风格的明显的不灵活性,但它可以帮助避免这类问题。例如,静态库可以通过 "#include "lib_api.h"提供其 API,而所有其他组织可以相对于用户不可见的位置 还有