0

0

c++中如何防止头文件重复包含_c++ #ifndef与#pragma once区别【实例】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-22 15:51:09

|

603人浏览过

|

来源于php中文网

原创

应优先使用 #ifndef / #define / #endif,因其是标准、可移植、可靠;#pragma once 虽简洁但非标准,存在文件系统依赖和兼容性风险。

c++中如何防止头文件重复包含_c++ #ifndef与#pragma once区别【实例】

#ifndef#pragma once 都能防止头文件重复包含,但它们机制不同、兼容性不同、行为边界也不同——选错可能在跨平台或大型项目中埋坑。

为什么重复包含头文件会出问题

多次包含同一头文件,会导致符号重定义(比如类重复声明、函数重复声明)、模板实例化冲突、编译变慢。C++ 标准不保证头文件被多次包含时的行为安全,必须主动防护。

常见触发场景:

  • 多个头文件都 #include "common.h",而它们又被同一个 .cpp 同时包含
  • 继承链中间接包含同一头文件(A.h → B.h → C.h,同时 A.h → C.h

#ifndef / #define / #endif 是标准、可控、可移植的方案

它依赖宏名唯一性,由预处理器在文本层面判断是否跳过内容。只要宏名不冲突,就可靠。

立即学习C++免费学习笔记(深入)”;

典型写法(注意命名规范):

笔尖Ai写作
笔尖Ai写作

AI智能写作,1000+写作模板,轻松原创,拒绝写作焦虑!一款在线Ai写作生成器

下载
#ifndef MYLIB_VECTOR_H_
#define MYLIB_VECTOR_H_

include

namespace mylib { template class vector { / ... / }; } // namespace mylib

endif // MYLIB_VECTORH

关键点:

  • 宏名建议用 大写 + 下划线 + 文件路径信息(如 UTILS_LOG_H_),避免和用户代码/第三方库冲突
  • 必须成对出现:#ifndef#endif 之间不能有未配对的条件编译指令
  • 支持所有符合标准的预处理器(GCC、Clang、MSVC、ICC 等),无兼容性风险
  • 即使头文件被 #include <...>#include "..." 同时引用,也能正确识别为同一文件(靠路径字符串匹配)

#pragma once 是编译器扩展,简洁但有隐含限制

它让编译器直接按物理文件路径做去重,不依赖宏名,写起来更轻量:

#pragma once

include

namespace mylib { template class vector { / ... / }; }

但它的问题藏在细节里:

  • 不是 C++ 标准特性,虽被 GCC/Clang/MSVC 广泛支持,但某些嵌入式工具链或老版本编译器(如早期 TI C++ 编译器)可能不识别
  • 对硬链接、符号链接、网络文件系统(NFS)、生成头文件(如通过 CMake configure_file 生成)等场景识别不稳定——同一逻辑头文件若路径不同,#pragma once 可能认为是两个文件
  • 无法处理“不同路径指向同一文件”的情况(例如 /src/a.h/build/src/a.h 是硬链接),而 #ifndef 因宏名相同仍能生效
  • 宏名冲突的风险被规避了,但换来的是对文件系统语义的强依赖

实际项目中怎么选

没有绝对优劣,只有上下文适配:

  • 开源库、跨平台 SDK、需长期维护的底层模块:优先用 #ifndef,确保可预测性和最大兼容性
  • 公司内部 MSVC/Clang 主导的项目,且构建环境统一、无符号链接/NFS:可用 #pragma once 提高可读性,但需在 CI 中验证所有目标平台
  • 混合使用?不推荐。同一项目中混用会让新人困惑,且 IDE 的头文件导航、静态分析工具可能表现不一致
  • 现代建议:用 #pragma once + 保留 #ifndef 注释作为兜底(非强制,仅提醒),但不要真写两套防护

真正容易被忽略的是:头文件防护只是第一道防线;如果头文件本身有定义非内联函数、全局变量或模板以外的实体,还需配合 inlinestaticextern 或定义分离(声明放头文件,定义放 .cpp)来避免 ODR 违规——防护宏管不了链接期错误。

相关专题

更多
typedef和define区别
typedef和define区别

typedef和define区别在类型检查、作用范围、可读性、错误处理和内存占用等。本专题为大家提供typedef和define相关的文章、下载、课程内容,供大家免费下载体验。

107

2023.09.26

define的用法
define的用法

define用法:1、定义常量;2、定义函数宏:3、定义条件编译;4、定义多行宏。更多关于define的用法的内容,大家可以阅读本专题下的文章。

335

2023.10.11

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

78

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

278

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1489

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

621

2023.11.24

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

6

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 3.4万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号