1.前言
C++中包含头文件存在两种不同的形式,尖括号<>和双引号"",其区别在于搜索范围和搜索顺序。
以Visual Studio 2022为例,我们创建一个工程,在里面添加主函数main.cpp的文件,以及头文件test.h
Project
├── main.cpp
└── test.h
2.搜索范围
<>只可以访问 系统目录下的头文件(.h),""可以访问 当前文件相对路径 + 系统目录下的头文件(.h) 。
使用#include <>系统会只会显示并搜索系统目录里的头文件。
因此#include <test.h>会报错。
#include <test.h> // 错误,在标准库内找不到test.h文件
使用#include ""系统会显示当前目录下的文件,但实际上也是可以包含系统目录里头文件的,只不过在编译器内没有显示而已。
由于test.h是我们在工程当中新创建的头文件,且位于main.cpp同一目录下,只能使用#include "test.h"来包含该文件。
#include "test.h" // Project\test.h
3.添加包含目录
通常我们的源码不可能全部在同一目录下,这样不利于代码后续的维护,可读性也会变得非常糟糕,因此需要添加包含目录。例如将整个工程源码的最外层添加进来,这样后续所有的include都可以从工程的入口找到对应的头文件源码。
对于Visual Studio,在 项目->属性->配置属性->C/C++->常规->附加包含目录。
4.搜索顺序
附加包含目录允许添加多个,且C++也允许包含相同名字的头文件。
这样就会带来一个问题,如果相同地址下存在相同名字的头文件,会出现头文件包含错误的问题,这是由没搞清#inlcude包含顺序所导致。
首先给出搜索顺序的结论:
#inlcude <> 从包含目录开始,按照顺序依次查找,最后到系统目录。
#include "" 从当前目录开始,然后是包含目录,按照顺序依次查找,最后到系统目录。
常见的几个问题,以如下文件结构举例,addr1和addr2是文件夹名称,都添加进附加包含目录内。
Project
├── main.cpp
├── addr1
├── test.h
├── addr2
├── test.h
└── test.h
1.某个同名头文件存在于多个包含目录的相同地址下,那么在搜索路径排在后面的文件就不会被包含,例如:
addr1和addr2都被添加进附加包含目录,那么对于main.cpp来说,addr2下的test.h就没有办法被直接包含。
2.由于搜索优先级的原因,会导致<>和""所包含的头文件不同,使用时应当注意。
#include <test.h> // Project\addr1\test.h
#include "test.h" // Project\test.h
通常尽可能少的将乱七八糟的地址添加进目录当中,例如只将整个工程的源码入口加入到附加包含目录,或者从更改命名规范上来屏蔽这类问题。
5.总结
搜索空间上: #include "" 大于 #inlcude <>,因为#include "" 总是会搜索当前路径。
搜索顺序上: #inlcude <> 总是从包含目录开始,#inlcude "" 总是从当前目录开始,然后搜索包含目录。两种搜索方式总是在找到对应文件的那一刻停止。
对于那些既可以使用""也可使用<>编译的头文件,例如标准库文件,建议使用<>,而当前目录下的文件可以省去前面的长串相对地址,这样可以在一定程度上提高代码的编译效率。