include的路径及顺序

本文介绍Google开源项目的头文件包含规范,包括标准的头文件包含顺序、按字母顺序排序的重要性以及平台特定代码的特殊情况处理。通过遵循这些规则,可以提高代码的可读性和维护性。
来源
小技巧
  • 使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖: 相关头文件, C 库, C++ 库, 其他库的 .h, 本项目内的 .h。
内容

项目内头文件应按照项目源代码目录树结构排列, 避免使用 UNIX 特殊的快捷目录 . (当前目录) 或 … (上级目录). 例如, google-awesome-project/src/base/logging.h 应该按如下方式包含:

#include "base/logging.h"

又如, dir/foo.cc 或 dir/foo_test.cc 的主要作用是实现或测试 dir2/foo2.h 的功能, foo.cc 中包含头文件的次序如下:

  1. dir2/foo2.h (优先位置, 详情如下)
  2. C 系统文件
  3. C++ 系统文件
  4. 其他库的 .h 文件
  5. 本项目内 .h 文件

这种优先的顺序排序保证当 dir2/foo2.h 遗漏某些必要的库时, dir/foo.cc 或 dir/foo_test.cc 的构建会立刻中止。因此这一条规则保证维护这些文件的人们首先看到构建中止的消息而不是维护其他包的人们。

dir/foo.cc 和 dir2/foo2.h 通常位于同一目录下 (如 base/basictypes_unittest.cc 和 base/basictypes.h), 但也可以放在不同目录下.

按字母顺序分别对每种类型的头文件进行二次排序是不错的主意。注意较老的代码可不符合这条规则,要在方便的时候改正它们。

您所依赖的符号 (symbols) 被哪些头文件所定义,您就应该包含(include)哪些头文件,前置声明 (forward declarations) 情况除外。比如您要用到 bar.h 中的某个符号, 哪怕您所包含的 foo.h 已经包含了 bar.h, 也照样得包含 bar.h, 除非 foo.h 有明确说明它会自动向您提供 bar.h 中的 symbol. 不过,凡是 cc 文件所对应的「相关头文件」已经包含的,就不用再重复包含进其 cc 文件里面了,就像 foo.cc 只包含 foo.h 就够了,不用再管后者所包含的其它内容。

举例来说, google-awesome-project/src/foo/internal/fooserver.cc 的包含次序如下:

#include "foo/public/fooserver.h" // 优先位置

#include <sys/types.h>
#include <unistd.h>

#include <hash_map>
#include <vector>

#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/public/bar.h"
例外

有时,平台特定(system-specific)代码需要条件编译(conditional includes),这些代码可以放到其它 includes 之后。当然,您的平台特定代码也要够简练且独立,比如:

#include "foo/public/fooserver.h"

#include "base/port.h"  // For LANG_CXX11.

#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11
<think>嗯,用户问的是C/C++中#include指令搜索头文件的路径顺序,我需要详细回答这个问题。首先,我得回忆一下相关的知识,可能需要结合之前学过的编译原理和GCC编译器的资料。 首先,用户的问题涉及到两种包含方式:#include <...>和#include "...",这两种的区别应该是搜索路径的不同。根据引用[1],双引号形式会先搜索当前文件所在目录,而尖括号形式则直接搜索系统路径。不过引用[3]提到,双引号如果在当前目录找不到,还是会去系统路径找,所以可能两种方式在某些情况下会有重叠,但优先顺序不同。 然后,需要分情况讨论。对于双引号的情况,路径顺序应该是怎样的呢?根据引用[2],双引号的搜索顺序是:1.当前目录,2.-I指定的目录,3.环境变量如C_INCLUDE_PATH等,4.编译器内定目录。而尖括号的情况则是跳过当前目录,直接按-I、环境变量、内定目录的顺序来找。 接下来,我需要把这些步骤整理清楚,可能分成几个部分,比如预处理阶段、两种包含方式的区别、环境变量的影响等。同时,用户可能对如何验证这些路径顺序感兴趣,所以可能需要提到使用编译命令如gcc -v来查看详细的搜索路径。 还有,用户可能在实际开发中遇到问题,比如头文件找不到,这时候需要解释如何通过调整包含路径或者正确使用引号与尖括号来解决问题。比如,如果是自己的头文件,应该用双引号并确保路径正确,或者使用-I参数添加目录。 另外,引用中提到的一些细节,比如第三方库的安装路径通常是在系统目录下,所以用尖括号更合适。而项目内部的头文件用双引号。同时,可以建议在不确定的情况下使用双引号,虽然可能稍微影响编译速度,但更保险。 还需要考虑不同编译器的差异,比如GCC和MSVC是否有不同的处理方式,但用户的问题可能主要集中在GCC上,所以可以主要讨论GCC的情况,可能简要提到其他编译器。 最后,生成相关问题,比如如何查看编译器搜索路径,如何解决头文件冲突,或者环境变量的设置方法。这些问题可以帮助用户进一步理解相关内容。</think>### C/C++头文件搜索路径顺序详解 在C/C++开发中,`#include`指令的搜索路径顺序直接影响编译结果。其规则根据**包含形式**(双引号`" "`或尖括号`< >`)和**编译器配置**分为以下几种情况: --- #### 一、双引号形式 `#include "xxx.h"` 1. **当前文件所在目录** 优先搜索包含该`#include`指令的源文件所在目录[^3]。 2. **-I参数指定目录** 按命令行中`-I`参数的顺序依次搜索,例如: ```bash gcc -I/path/to/custom/include main.c ``` 3. **环境变量定义的路径** 依次搜索以下环境变量(若存在): - C程序:`C_INCLUDE_PATH` - C++程序:`CPLUS_INCLUDE_PATH` - 通用:`CPATH`[^2] 4. **编译器内置路径** 最后搜索编译器默认的系统路径(如`/usr/include`),可通过命令查看: ```bash cpp -v /dev/null -o /dev/null 2>&1 | grep "include" ``` --- #### 二、尖括号形式 `#include <xxx.h>` 1. **-I参数指定目录** 优先按`-I`参数顺序搜索。 2. **环境变量定义的路径** 与双引号形式的环境变量规则一致[^2]。 3. **编译器内置路径** 直接搜索系统标准路径(跳过当前目录)。 --- #### 三、关键区别与建议 | 特性 | 双引号`" "` | 尖括号`< >` | |--------------------|------------------------|-----------------------| | 当前目录搜索 | ✔️ 优先 | ❌ 跳过 | | 系统路径搜索 | ✔️ 后备 | ✔️ 直接 | | 适用场景 | 项目本地头文件 | 系统/第三方库头文件 | > **建议**:自定义头文件使用`" "`,系统库使用`< >`以明确语义[^3]。若不确定,统一使用`" "`可保证兼容性(牺牲微小性能)。 --- #### 四、验证搜索路径 通过编译器调试选项查看实际搜索顺序: ```bash gcc -E -Wp,-v main.c # 输出详细搜索路径 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值