我用以下文件夹结构进行了测试:
MainFolder
main.cpp
LibraryFile.h
Files
LibraryFile.h
Library1Name
MainHeader.h
LibraryFile.h
Files
LibraryFile.h
Library2Name
MainHeader.h
LibraryFile.h
Files
LibraryFile.h
假设
MainFolder
(根)文件夹位于包含路径中,没有其他文件夹。
现在,在
main.cpp
,我做:
#include "Library1Name/MainHeader.h"
MainHeader.h
和Library1
中的Library2
都包括:
#include "LibraryFile.h"
#include "Files/LibraryFile.h"
这里的要点是在所有三个版本之间创建完全相同的文件夹结构和名称:
The Library1 version
The Library2 version
The Root Folder version
据我所知,现在引用
Library1
中的这些文件,或者,看到主根文件夹位于包含路径中,引用根版本之间存在潜在的冲突。
问题1:这里的顺序有定义吗?
在我的系统上,它选择里面的那个
Library1
。所以,没有发生冲突。但是,我们只能说存在冲突,因为我相信我之前就有过冲突,添加 "./"
作为包含路径会产生什么效果?
例如,在
main.cpp
中:
#include "Library1Name/MainHeader.h"
然后在
Library1
MainHeader
:
#include "./LibraryFile.h"
#include "./Files/LibraryFile.h"
从我的测试来看,当它确实发生冲突时(尽管我无法再重现冲突),添加
"./"
解决了冲突。
我的理论是,如果你这样做,编译器将无法选择根文件夹版本,因为你已经指定了
"./"
,这具体意味着相对于你编写它的文件。需要澄清的是,"./"
并不意味着包含在.cpp
文件中之后的文件夹路径,这意味着“CPP文件的位置”。相反,它总是指“写入"./"
的文件的位置。这是头文件。
问题 2:
"./"
总是这样做吗?
此外,考虑我们将路径
"MainFolder/Library2Name"
添加到包含路径中。这意味着我们会引入另一个冲突,但是,正如我之前所说,指定 "./"
可以消除所有冲突。
我在多大程度上是对的?
此外,
#include ""
和#include <>
之间也有区别,但由于这确实很复杂,所以让我们忘记<>
并专注于""
。我做的测试是这里。
所有这些都是由实现定义的。具体来说([cpp.include]/1-3):
指令应标识可由实现处理的头文件或源文件。#include
- 表单的预处理指令
# include < h-char-sequence > new-line
在一系列实现定义的位置中搜索由和<
分隔符之间的指定序列唯一标识的标头,并导致用标头的整个内容替换该指令。如何指定位置或识别标头是实现定义的。>
- 表单的预处理指令
# include " q-char-sequence " new-line
导致将该指令替换为由 " 分隔符之间的指定序列标识的源文件的全部内容。在实现定义的中搜索指定的源文件 方式。如果不支持此搜索,或者搜索失败,则该指令将被重新处理,就像它读取的那样
# include < h-char-sequence > new-line
具有与原始指令相同的包含序列(包括字符,如果有的话)。>
因此,几乎所有关于在哪里进行搜索、以什么顺序等进行搜索的内容都是由实现定义的。实际上只有一个相当简单的规则:像
#include "foo"
这样的东西必须搜索与 #include <foo>
相同的所有位置,但可能还有更多 - 如果有任何“除此之外的其他”,则这些位置优先。
除此之外,一切都取决于编译器。