我已经回顾了问题How to use include directive correctly和C++ #include semantics并且都没有解决这个问题 - 当我输入标题时,SO也没有提出其他问题......
如果有的话,写作的好处是什么:
#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
'指令来查找标题的情况下逃脱,但是失去灵活性,以及在子程序中编译的复杂性子目录等似乎超过了好处。
那么,我是否忽视了一项福利?
感谢您的投入。我认为大家一致认为,使用“......”的符号没有任何重大好处,我忽略了。一般来说,我喜欢“somewhere / header.h”符号;我确实在新项目中使用它。我正在努力的是新事物。
其中一个问题是有各种标题集,通常有一个前缀,如rspqr.h
,rsabc.h
,rsdef.h
,rsxyz.h
。这些都与rsmp
目录中的代码有关,但是有些标题位于rsmp
中,而其他标题位于中央include目录中,其中没有rsmp
等子目录。 (并重复代码的其他各个方面;在多个位置都有标题,需要其他位代码随机使用。)移动内容是一个主要问题,因为多年来代码变得如此复杂。并且makefile与提供-I
选项不一致。总而言之,这是一个悲伤的故事,讲述了几十年来不那么温和的疏忽。在不破坏任何东西的情况下解决所有问题将是一项漫长而乏味的工作。
我更喜欢路径语法,因为它非常清楚头文件所属的命名空间或模块。
#include "Physics/Solver.h"
非常自描述而不需要每个模块将其名称作为头文件的前缀。
我几乎从不使用“..”语法,而是我的项目包括指定正确的基本位置。
#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
指令。此外,如果你以后从-I./lib
路径中删除#include
,那么你打破./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"
。假设“projectname”可能是唯一的,这在大多数情况下不会导致名称冲突或模糊。如果绝对必要,您还可以使用include路径和/或make的VPATH
功能将项目的物理布局分割为多个目录(例如,为了适应特定于平台的自动生成的代码;当您使用#include "../../somefile.h"
时,这确实会崩溃)。
IANALL,但我不认为你应该把..
放在实际的C或C ++源文件中,因为那不是便携式的,而且标准不支持它。这类似于在Windows上使用\
。只有在编译器无法使用任何其他方法时才能执行此操作。
将源树视为嵌套命名空间,包含路径允许您将目录拉入此命名空间的根目录。问题是如何为代码库形成逻辑命名空间,而不管代码在磁盘上的组织方式。
我会避免像这样的路径:
"include/foo/bar.h"
- “包括”似乎不合逻辑和多余"../foo/bar.h"
- “..”假定相对位置并且是脆弱的"bar.h"
- 除非bar.h在当前目录中,否则会污染全局命名空间并要求模糊。就个人而言,我倾向于在我的项目中添加如下路径包括路径 - "..;../..;../../..;../../../.."
。
这允许您对#include
s应用一种隐藏规则,并允许在不破坏其他代码的情况下自由移动标题。当然,这是以引入绑定到错误的头文件的风险为代价的,如果您不小心,因为非完全限定的名称可能(或变得时间)不明确。
我倾向于在公共标题中完全限定#include
s,因此任何使用我的代码的第三方都不需要将"..;../..;../../..;../../../.."
添加到他们的项目中 - 这只是我的私有代码和构建系统的便利。
因为那时你把文件放在项目的根目录下,当你把它检查到源代码控制中,而另一个开发人员将它检查到本地系统的不同位置时,事情仍然有效。
具有相对路径的Windows上的另一个问题是MAX_PATH。这将触发编译问题,例如交叉编译为Android和你的路径长度超过260。
在以下情况下,使用一个或多个“#include ""
”序列开始../
指令的路径:
提供代码库包含错误的位置以及随后导致难以诊断的故障的示例总是很容易的。但是,即使您的项目没有故障,如果依靠绝对路径指定相对于彼此的文件,它也可能被第三方滥用。
例如,考虑以下项目布局:
./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?我们考虑两个选择:
#include <bar/header2.h>
假设your_lib / include和their_lib / include都被引用为标题搜索路径(例如,使用GCC的-I
或-isystem
选项),那么选择哪个header2.h对搜索这两个路径的顺序很敏感。#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)。
回答其他答案中的一些论点:
""
上解释<>
和likely originates之间的区别。)..
”。