代码之家  ›  专栏  ›  技术社区  ›  Jonathan Leffler

相对路径(如标题的“./include/header.h”)有什么好处?

  •  49
  • Jonathan Leffler  · 技术社区  · 16 年前

    How to use include directive correctly C++ #include semantics 当我键入标题时,这两个问题都没有解决,其他人也没有提出。。。

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

    #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 指令来查找标题,但灵活性的丧失以及在子目录中编译的复杂性等似乎超过了其好处。

    那么,我是否忽视了一个好处?


    谢谢你的投入。我认为大家的共识是,使用“.”表示法没有任何我忽略的主要好处。一般来说,我喜欢“某处/header.h”符号;我确实在新项目中使用它。我正在做的那件不是新的。

    其中一个问题是有各种各样的头,通常带有前缀,例如 rspqr.h , rsabc.h , rsdef.h , rsxyz.h rsmp 目录,但某些标头位于 还有一些位于中心include目录中,该目录没有子目录,例如 在里面。(并重复代码的其他各个区域;在多个位置有头,其他代码位随机需要这些头。)移动内容是一个主要问题,因为这些年来代码变得如此复杂。并且生成文件不一致,其中 -我

    7 回复  |  直到 7 年前
        1
  •  46
  •   Andrew Grant    16 年前

    我更喜欢路径语法,因为它非常清楚头文件所属的名称空间或模块。

    #include "Physics/Solver.h"
    

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

        2
  •  26
  •   bk1e    16 年前

    问题在于 #include "../include/header.h"

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

    假设您正在使用包含路径运行编译器 -I. -I./lib

    • ./lib/library.c 能行 #包括“./include/header.h” ,这是有道理的。
    • ./lib/feature/feature.c 也可以 #包括“./include/header.h” ,尽管这毫无意义。这是因为编译器将尝试 #include #包括 与每个指令相关的指令 -I 进入 路径

    此外,如果以后删除 -I./lib #包括 路,然后你打破 ./lib/feature/feature.c .

    我认为以下内容更可取:

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

    -I. ,然后两者兼而有之 library.c feature.c #include "projectname/include/header.h" VPATH 如果绝对必要,可以将项目的物理布局拆分到多个目录中(例如,为了适应特定于平台的自动生成代码;当您使用 #include "../../somefile.h" ).

        3
  •  10
  •   John McFarlane    6 年前

    开始你的人生之路 #include "" 具有一个或多个序列的指令” ../ “何时:

    • 您希望避免关于将包含哪个文件的歧义。

    提供一个示例总是很容易的,说明您的代码库在哪里包含错误,以及这会在哪里导致难以诊断的故障。但是,即使您的项目没有故障,如果您依赖绝对路径来指定彼此相对的文件,第三方也可能滥用该项目。

    例如,考虑下面的项目布局:

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

    您的_lib/include/foo/header1.h 包括 ? 让我们考虑两种选择:

    1. #include <bar/header2.h>

      兼而有之 你的库/包括 他们的_lib/包括 引用为标题搜索路径(例如,使用GCC -I -isystem 选项),然后选择哪个选项 校长2.h

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

      编译器将搜索的第一个位置是 您的_lib/include/foo/header1.h 你的_lib/include/foo/ 你的_lib/include/bar/header2.h

    在这种情况下,我强烈推荐选项2),理由如下。

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

    • @安德鲁·格兰特 says

      …它非常清楚头文件所属的名称空间或模块。

    • @bk1e says :

      我认为,相对路径只有在极少数情况下才会意外地起作用,因为项目从一开始就中断了,而且很容易修复。在不引起编译器错误的情况下经历这样的名称冲突似乎不太可能。一种常见的情况是,依赖项目的文件包含一个标题,其中包含另一个标题。在独立于依赖项目进行编译时,编译测试套件应导致“无此类文件或目录”错误。

    • says

      …这是不可移植的,标准不支持它。

      ISO C标准可能没有规定编译或运行程序所依据的系统的所有细节。这并不意味着它们不受支持,只是标准没有过度指定运行C的平台。(如何区分 "" <> 在共同的现代系统上进行解释 likely originates 在POSIX标准中。)

    • @丹尼尔·保尔 says

      脆弱如何?可能对两个文件的搭配很敏感。因此“ .. “应仅(且始终)在包含文件的作者控制其位置时使用。

        4
  •  9
  •   Jonathan Leffler    9 年前

    .. 在实际的C或C++源文件中,因为这不是可移植的,标准不支持它。这类似于使用 \ 在窗户上。仅当编译器无法使用任何其他方法时才执行此操作。

        5
  •  2
  •   Jonathan Leffler    9 年前

    将源树视为一个嵌套的名称空间,include路径允许您将目录拉入该名称空间的根目录中。然后,问题是为代码库形成一个逻辑名称空间,而不管代码在磁盘上是如何组织的。

    我会避免这样的路径:

    • "include/foo/bar.h" “包含”似乎不合逻辑且多余
    • "../foo/bar.h"
    • "bar.h" 除非bar.h在当前目录中,否则这会污染全局名称空间并导致歧义。

    就我个人而言,我倾向于在我的项目include path中添加如下路径 "..;../..;../../..;../../../.."

    这允许您将某种隐藏规则应用于 #include 并允许在不破坏其他代码的情况下自由移动标题。当然,这是以引入绑定到错误头文件的风险为代价的,如果您不小心,因为非完全限定名可能(或随着时间的推移变得)不明确。

    我倾向于完全合格 #包括 对于他们的项目来说,这只是我的私有代码和构建系统的一个方便。

        6
  •  2
  •   MadSystem    7 年前

        7
  •  1
  •   Joel Coehoorn    16 年前

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

        8
  •  0
  •   oclyke    4 年前

    #include "./lib/subdir/~/subsubsubsubdir/header.h" ... 当在一个非常大的项目上工作时,你可能需要 "-I./~" 链接行上的选项。在我当前的一个项目中,这些选项占用的字符数接近40k,这会由于命令行限制而导致错误。

    虽然通常我不喜欢那种包含路径样式的明显僵化,但它可以帮助避免此类问题。例如,静态库可以通过 "#include "lib_api.h"