当前位置: 首页 > news >正文

C++ include头文件的顺序以及双引号““和尖括号<>的区别

本文章进一步详细解释 #include 的头文件包含机制,包括搜索路径的处理、双引号 "" 和尖括号 <> 在不同环境中的使用差异,以及它们的底层机制。

1. 头文件包含机制和搜索路径详解

#include 是一个预处理指令,用于在编译前将指定的头文件的内容插入到当前源文件中。在 C++ 编译过程中,头文件的查找顺序和搜索路径的选择会影响项目的编译成功与否。

双引号 "" 的搜索路径机制

当使用双引号 #include "filename" 包含头文件时,编译器通常按照以下顺序查找头文件:

  1. 当前文件所在的目录
    • 编译器首先查找与当前源文件同目录的头文件。这是因为我们通常使用双引号来包含本地定义的头文件(如类定义的 .h 文件)。
  2. 包含该文件的文件夹
    • 如果该源文件本身是通过 #include 被其他文件引用的,编译器会在最先引用该文件的文件夹内查找。
  3. 指定的项目包含路径(通过编译器参数指定的路径,例如 -I 选项):
    • 编译器会查找通过编译器命令行参数指定的头文件路径(-I/path/to/include)。这个路径可以是多个目录,依赖于构建系统的设置。
  4. 全局系统路径
    • 如果前面的路径中没有找到文件,编译器会在全局头文件目录中查找。通常这些路径是操作系统或者 IDE 预先配置好的系统路径,比如 /usr/include(Linux 系统)或者 C:\Program Files\(Windows 系统)。
尖括号 <> 的搜索路径机制

当使用尖括号 #include <filename> 包含头文件时,编译器仅在全局或系统路径中查找头文件,忽略当前目录。这是为了更高效地查找标准库和第三方库中的头文件。查找路径如下:

  1. 标准库路径

    • 编译器首先在 C++ 标准库的路径中查找头文件。这些路径可能包含 <iostream>, <vector>, <string> 等标准库文件。
  2. 系统库路径

    • 然后,编译器会查找系统头文件路径。比如,在 Linux 系统中,常见路径为 /usr/include/usr/local/include,而在 Windows 系统中,可能是 C:\Program Files (x86)\Microsoft Visual Studio\
  3. 指定的头文件路径

    • 依赖于编译器设置,可能还会根据用户指定的第三方库路径(如通过 -I 指定的路径)来查找第三方库的头文件,例如 Boost、Qt 等。
双引号和尖括号的选择与差异
  • 使用双引号 "" 更适合引用 项目内部 或者 本地定义的头文件,因为它会首先查找当前文件目录,确保本地头文件的优先级较高。这种方式适用于项目间的模块化开发。
  • 使用尖括号 <> 通常用于 标准库外部库 的头文件,避免在当前目录下无意中引用到同名的头文件。
更详细的搜索过程比较
使用符号查找顺序适用场景
双引号 ""1. 当前目录
2. 引用文件所在目录
3. 编译器指定的项目路径(如 -I
4. 系统路径
用于引用本地的头文件
尖括号 <>1. 标准库路径
2. 系统路径
3. 第三方路径
用于标准库和外部库的头文件
编译器选项与头文件路径

在使用编译器时,可以通过选项配置头文件的查找路径。例如:

  • GCC/Clang

    • -I:指定额外的头文件路径。例如,g++ -I/path/to/headers main.cpp 会告诉编译器在 /path/to/headers 中查找头文件。
  • Visual Studio

    • 在项目属性的 "C/C++" > "附加包含目录" 中,可以指定额外的包含目录。编译器会在这些目录中查找双引号 "" 和尖括号 <> 所包含的头文件。
  • CMake

    • 使用 include_directories()target_include_directories() 指定头文件的搜索路径。

2. 双引号和尖括号的深层机制

双引号和尖括号的主要区别在于它们告诉编译器如何查找文件的路径。尖括号中的头文件往往是一些不常修改的外部依赖,比如标准库文件、系统级文件或者第三方库,而双引号中的头文件是用户自定义的文件,更容易发生变化。因此,双引号和尖括号的查找路径和优先级设计不同。

双引号 vs 尖括号查找行为

双引号 "filename":
1. 查找当前目录/源文件目录
2. 查找编译器路径(通过 -I 指定)
3. 查找标准系统路径

尖括号 <filename>:
1. 查找标准系统路径
2. 查找第三方路径

3. #include 的例子与实践

包含自定义头文件的实例

#include "MyClass.h" // 当前目录查找
#include "subfolder/Helper.h" // 指定子文件夹查找

#include <iostream> // 系统库查找,标准C++库
#include <cmath>    // 系统路径下的数学库

在这个例子中,"MyClass.h""subfolder/Helper.h" 都是项目内的文件,编译器会从源文件所在的目录或项目结构中的路径查找。<iostream><cmath> 是标准库的头文件,因此编译器直接在标准路径中查找。

4. 如何正确组织头文件

为了避免潜在的查找冲突和提高编译速度,建议遵循以下头文件组织原则:

  1. 使用前向声明

    • 尽量在头文件中使用前向声明来减少包含不必要的头文件。例如,在类成员中引用其他类的指针时,可以通过前向声明避免引入整个类的定义。

                class MyClass; // 前向声明
                class AnotherClass {
                    MyClass* ptr; // 使用指针或引用即可避免包含整个 MyClass 头文件
                };

        

      2.防止多次包含(Include Guard)

  • 为了避免头文件的多次包含,常用的做法是使用包含防护,即 #ifndef#define#endif 组合,或者在现代 C++ 中使用 #pragma once
  • // MyClass.h
    #ifndef MYCLASS_H
    #define MYCLASS_H

    class MyClass {
        // Class Definition
    };

    #endif // MYCLASS_H

  1. 确保头文件独立

    • 每个头文件应该可以独立包含,不依赖其他头文件的顺序。通过包含防护和适当的前向声明,避免头文件之间的复杂依赖关系。

5. 总结

  • 双引号 "":优先用于包含项目中的本地文件,编译器会先从当前目录查找,再到系统路径查找。
  • 尖括号 <>:用于包含标准库或外部库文件,编译器直接从系统路径查找。
  • 头文件包含顺序:优先包含与当前实现文件相关的头文件,然后是标准库头文件,接着是第三方库,最后是项目内部其他模块的头文件。

http://www.lryc.cn/news/459820.html

相关文章:

  • Flutter鸿蒙版本灵活使用方法间的回调处理复杂化的逻辑
  • 视频号直播自动回复与循环发送话术-自动化插件
  • springcloud之服务集群注册与发现 Eureka
  • C++:模拟实现list
  • 解锁5 大无水印热门短视频素材库
  • 【电商购物管理系统】Python+Django网页界面平台+商品管理+数据库
  • AD9248驱动的简易示波器设计——FPGA学习笔记21
  • 微软十月补丁星期二发现了 118 个漏洞
  • 到底是微服务,还是SOA?
  • JDK17常用新特性
  • 【分布式微服务云原生】探索负载均衡的艺术:深入理解与实践指南
  • 拥抱云原生
  • 关于使用若依并快速构建系统的操作指南
  • 【分布式微服务云原生】 选择SOAP还是RESTful API?深入探讨与实践指南
  • HarmonyOS NEXT 应用开发实战(五、页面的生命周期及使用介绍)
  • C# 比较两个集合和比较对象
  • Spark高级用法-自定义函数
  • 『Mysql进阶』Mysql explain详解(五)
  • 【工具】音视频翻译工具基于Whisper+ChatGPT
  • 学成在线——关于nacos配置优先级的坑
  • Nginx在Windows Server下的启动脚本
  • 【国科大】C++程序设计秋季——五子棋
  • Docker 环境下多节点服务器监控实战:从 Prometheus 到 Grafana 的完整部署指南
  • 【动手学深度学习】6.3 填充与步幅(个人向笔记)
  • 【宝可梦】游戏
  • docker启动的rabbitmq如何启动其SSL功能
  • 易基因: cfMeDIP-seq揭示cfDNA甲基化高效区分原发性和转移性前列腺|Nat Commun
  • CMake 教程跟做与翻译 4
  • MySQL面试题分享
  • vue路由缓存问题