【C/C++】不同防止头文件重复包含的措施

文章目录

  • #pragma once vs #ifndef 文件宏
    • 1 原理层面区别(core)
    • 2 关键区别与优缺点分析
    • 3 总结与最佳实践

#pragma once vs #ifndef 文件宏

在 C/C++ 中,#pragma once 和传统的文件宏守卫 (#ifndef HEADER_H #define HEADER_H ... #endif) 都用于防止头文件在单个翻译单元(通常是一个 .cpp 文件及其递归包含的所有头文件)中被重复包含多次。

1 原理层面区别(core)

  1. #pragma once (编译器指令):

    • 底层处理: 这是一个编译器特定的指令(尽管几乎所有现代编译器都支持它)。当编译器遇到 #pragma once 时:
      • 它会在其内部维护一个数据结构(通常是一个集合或哈希表),记录已经包含过哪些物理文件。
      • 这个记录通常基于文件的唯一标识符,在大多数系统上是文件的绝对路径(inode 或其他底层文件系统标识符也可能参与)。
      • 当编译器再次遇到包含同一个物理文件的 #include 指令时(基于这个唯一标识符判断),它会直接跳过包含该文件的整个内容。
    • 本质: 编译器基于文件的物理身份(路径/inode)来防止重复包含。它不需要查看或修改头文件的内容本身。
  2. 文件宏守卫 (#ifndef HEADER_H / #define HEADER_H / #endif) (预处理器机制):

    • 底层处理: 这是一个预处理器机制,发生在编译器进行真正的词法分析、语法分析之前。
      • 当预处理器处理头文件时,第一次遇到 #ifndef HEADER_H 时,因为 HEADER_H 尚未定义,条件为真。
      • 接着它执行 #define HEADER_H,将这个宏名放入预处理器维护的符号表中。
      • 然后处理头文件内容直到 #endif
      • 如果同一个翻译单元中再次尝试包含该头文件,预处理器再次遇到 #ifndef HEADER_H。此时 HEADER_H 已在符号表中定义,因此条件为假。预处理器会跳过从 #ifndef 到匹配的 #endif 之间的所有内容。
    • 本质: 预处理器基于一个在头文件内容中手动定义的、唯一的宏名称(HEADER_H)来防止重复包含。它依赖于文本替换和宏定义状态。

2 关键区别与优缺点分析

特性#pragma once文件宏守卫 (#ifndef HEADER_H)
标准合规性非标准 (但被所有主流编译器广泛支持:MSVC, GCC, Clang, ICC)标准 C/C++ (由语言标准保证)
底层机制编译器 基于物理文件标识符 (路径/inode)预处理器 基于宏名称在符号表中的存在性
唯一性要求由文件系统路径/标识符保证(通常可靠)由程序员手动确保宏名称全局唯一 (易出错,如复制粘贴头文件导致冲突)
处理速度通常更快:编译器只需检查文件ID集合。首次包含后,后续包含几乎立即跳过。可能稍慢:预处理器每次都需要打开文件(或缓存内容),查找宏定义状态。即使跳过内容,也可能需要词法扫描到 #endif
符号链接/硬链接行为取决于编译器实现:大多数编译器基于最终物理文件(inode),因此符号链接通常能正确处理。不同路径指向同一物理文件也能正确处理。基于包含指令的路径:如果通过不同路径(符号链接或直接路径)包含同一个物理文件,预处理器看到的是不同的宏定义指令(不同文件名),导致重复包含。
文件内容依赖无依赖:即使头文件内容为空或无效,只要指令存在就有效。强依赖:宏定义必须正确、唯一地写在文件开头和结尾。
拷贝文件问题拷贝头文件:视为不同物理文件,会被包含多次。拷贝头文件:如果宏名不同,会被包含多次;如果宏名相同,后续拷贝被跳过(但这是错误,拷贝文件应有独立宏名)。
跨平台/编译器依赖编译器支持(虽然现在支持极广),理论上不如宏守卫可移植。标准机制,可移植性最高。
错误处理重复包含通常被静默跳过。宏名冲突会导致意外的跳过或包含。

3 总结与最佳实践

  1. #pragma once 的优势:
    • 简洁: 一行代码搞定。
    • 不易出错: 无需发明唯一宏名,避免命名冲突。
    • 通常更快: 编译器优化更直接。
    • 处理链接文件更可靠: 对同一物理文件的不同路径包含更安全。
  2. 文件宏守卫的优势:
    • 标准合规: 100% 符合 C/C++ 标准。
    • 最大可移植性: 适用于任何符合标准的编译器(包括非常古老的或嵌入式编译器)。
    • 对文件副本更明确: 物理副本需要不同的宏名(这是应该的),行为更直观(虽然宏名冲突是问题)。
  3. 最佳实践 (现代 C/C++ 开发):
    • 优先使用 #pragma once: 对于绝大多数现代项目(使用 GCC >= 3.4, Clang, MSVC, ICC 等),#pragma once 是推荐的首选方式。它的简洁性、性能和避免宏名冲突的优势显著。
    • 如果需要最大可移植性或目标编译器未知: 使用文件宏守卫。
    • 混合使用 (常见且安全): 很多项目/IDE 生成的代码同时使用两者:
      #pragma once
      #ifndef MYPROJECT_UTILS_H
      #define MYPROJECT_UTILS_H
      // ... 头文件内容 ...
      #endif // MYPROJECT_UTILS_H
      
      • #pragma once 提供主要保护和性能。
      • 文件宏守卫提供后备机制,万一编译器不支持 #pragma once(极罕见)或遇到符号链接路径处理不一致(理论情况),也能保证正确性。同时也清晰标明了文件结束位置。

底层处理的本质区别一句话概括:#pragma once 是编译器问“这个物理文件我见过吗?”,文件宏守卫是预处理器问“这个特定的宏名字我定义过吗?”。 现代开发中,#pragma once 因其简洁高效已成为事实标准。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/82745.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java-springboot文件上传校验之只允许上传excel文件,且检查不能是脚本或者有害文件或可行性文件

四重验证机制: 文件扩展名检查(.xlsx/.xls)MIME类型检查文件魔数验证(真实文件类型)可执行文件特征检测 防御措施: 使用try-with-resources确保流关闭限制文件大小防止DoS攻击使用Apache POI的FileMagic进…

不确定性分析在LEAP能源-环境系统建模中的整合与应用

本内容突出与实例结合,紧密结合国家能源统计制度及《省级温室气体排放编制指南》,深入浅出地介绍针对不同级别研究对象时如何根据数据结构、可获取性、研究目的,构建合适的能源生产、转换、消费、温室气体排放(以碳排放为主&#…

高性能分布式消息队列系统(四)

八、客户端模块的实现 客户端实现的总体框架 在 RabbitMQ 中,应用层提供消息服务的核心实体是 信道(Channel)。 用户想要与消息队列服务器交互时,通常不会直接操作底层的 TCP 连接,而是通过信道来进行各种消息的发布…

QPair 类说明

QPair 类说明 QPair 是一个模板类&#xff0c;用于存储一对数据项。 头文件&#xff1a; cpp #include <QPair> qmake 配置&#xff1a; QT core 所有成员列表&#xff08;包括继承成员&#xff09; 公共类型 类型定义说明first_type第一个元素的类型&#xff…

4.大语言模型预备数学知识

大语言模型预备数学知识 复习一下在大语言模型中用到的矩阵和向量的运算&#xff0c;及概率统计和神经网络中常用概念。 矩阵的运算 矩阵 矩阵加减法 条件&#xff1a;行数列数相同的矩阵才能做矩阵加减法 数值与矩阵的乘除法 矩阵乘法 条件&#xff1a;矩阵A的列数 矩阵…

uniapp 设置手机不息屏

在使用 UniApp 开发应用时&#xff0c;有时需要在设备长时间未操作时实现息屏保护功能&#xff0c;以节省电量和保护屏幕。以下是如何在 UniApp 中实现这一功能的步骤。 示例一 // 保持屏幕常亮 uni.setKeepScreenOn({keepScreenOn: true });// 监听应用进入后台事件 uni.onH…

智能推荐系统:协同过滤与深度学习结合

智能推荐系统&#xff1a;协同过滤与深度学习结合 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 智能推荐系统&#xff1a;协同过滤与深度学习结合摘要引言技术原理对比1. 协同过滤算法&#xff1a;基于相似性的推…

使用Python和OpenCV实现图像识别与目标检测

在计算机视觉领域&#xff0c;图像识别和目标检测是两个非常重要的任务。图像识别是指识别图像中的内容&#xff0c;例如判断一张图片中是否包含某个特定物体&#xff1b;目标检测则是在图像中定位并识别多个物体的位置和类别。OpenCV是一个功能强大的开源计算机视觉库&#xf…

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…

Splash动态渲染技术全解析:从基础到企业级应用(2025最新版)

引言 在Web 3.0时代&#xff0c;87%的网站采用JavaScript动态渲染技术。传统爬虫难以应对Ajax加载、SPA应用等场景&#xff0c;Splash作为专业的JavaScript渲染服务&#xff0c;凭借​​Lua脚本控制​​和​​异步处理能力​​&#xff0c;已成为动态数据抓取的核心工具。本文…

【应用】Ghost Dance:利用惯性动捕构建虚拟舞伴

Ghost Dance是葡萄牙大学的一个研究项目&#xff0c;研究方向是探索人与人之间的联系&#xff0c;以及如何通过虚拟舞伴重现这种联系。项目负责人Cecilia和Rui利用惯性动捕创造出具有流畅动作的虚拟舞伴&#xff0c;让现实中的舞者也能与之共舞。 挑战&#xff1a;Ghost Danc…

广目软件GM DC Monitor

广目&#xff08;北京&#xff09;软件有限公司成立于2024年&#xff0c;技术和研发团队均来自于一家具有近10年监控系统研发的企业。广目的技术团队一共实施了9家政府单位、1家股份制银行、1家芯片制造企业的数据中心监控预警项目。这11家政企单位由2家正部级、1家副部级、6家…

12-Oracle 23ai Vector 使用ONNX模型生成向量嵌入

一、Oracle 23ai Vector Embeddings 核心概念​ 向量嵌入&#xff08;Vector Embeddings&#xff09;​​ -- 将非结构化数据&#xff08;文本/图像&#xff09;转换为数值向量 - - 捕获数据的语义含义而非原始内容 - 示例&#xff1a;"数据库" → [0.24, -0.78, 0.5…

用 NGINX 构建高效 POP3 代理`ngx_mail_pop3_module`

一、模块定位与作用 协议代理 ngx_mail_pop3_module 让 NGINX 能够充当 POP3 代理&#xff1a;客户端与后端 POP3 服务器之间的所有请求均转发到 NGINX&#xff0c;由 NGINX 负责与后端会话逻辑。认证方式控制 通过 pop3_auth 指令指定允许客户端使用的 POP3 认证方法&#xf…

每日算法 -【Swift 算法】三数之和

Swift&#xff5c;三数之和&#xff08;3Sum&#xff09;详细题解 注释 拓展&#xff08;LeetCode 15&#xff09; ✨题目描述 给你一个包含 n 个整数的数组 nums&#xff0c;判断 nums 中是否存在三个元素 a, b, c&#xff0c;使得 a b c 0。请你找出所有和为 0 且不重…

服务器磁盘空间被Docker容器日志占满处理方法

事发场景&#xff1a; 原本正常的服务停止运行了&#xff0c;查看时MQTT服务链接失败&#xff0c;查看对应的容器服务发现是EMQX镜像停止运行了&#xff0c;重启也是也报错无法正常运行&#xff0c;报错如下图&#xff1a; 报错日志中连续出现两个"no space left on devi…

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…

Linux中shell编程表达式和数组讲解

一、表达式 1.1 测试表达式 样式1: test 条件表达式 样式2: [ 条件表达式 ] 注意&#xff1a;以上两种方法的作用完全一样&#xff0c;后者为常用。但后者需要注意方括号[、]与条件表达式之间至少有一个空格。test跟 [] 的意思一样条件成立&#xff0c;状态返回值是0条件不成…