C++防止头文件被重复引入的3种方法(详解版)

【C++进阶之路】C++防止头文件被重复引入的3种方法! 在之前我们详细介绍了 C 语言中如何使用宏定义(#ifndef / #define / #endif)来有效避免头文件被重复 #include,此方式在 C++ 多文件编程中也很常用。 举个例子,如下是一个 C++ 项目,其内部含有 school.h 和 student.h 这 2 个头文件以及 main.cpp 源文件,其各自包含的代码为: //student.h class Student { //...... }; //school.h #include "student.h".. 阅读详情
AI摘要

本文介绍了C++中预防头文件重复包含的三种方法:使用宏定义、#pragma once及_Pragma操作符。通过实例说明如何避免重复引入导致的问题。

转自http://c.biancheng.net/view/7636.html

《防止C语言头文件被重复包含》一节中,详细介绍了 C 语言中如何使用宏定义(#ifndef / #define / #endif)来有效避免头文件被重复 #include,此方式在 C++ 多文件编程中也很常用。

举个例子,如下是一个 C++ 项目,其内部含有 school.h 和 student.h 这 2 个头文件以及 main.cpp 源文件,其各自包含的代码为:

//student.h
class Student {
    //......
};

//school.h
#include "student.h"
class School {
    //......
private:
    Student stu[50];
};

//main.cpp
#include "student.h"
#include "school.h"
int main() {
    //......
    return 0;
}

运行此项目读者会发现,编译器报“Student 类型重定义”错误。这是因为在 school.h 文件中已经 #include 了一次 "student.h",而在 main.cpp 主程序又同时 #include 了 "school.h" 和 "student.h",即 Student 类的定义被引入了 2 次,C++不允许同一个类被重复定义。

有读者可能想到,既然 School.h 文件中已经引入了 Student 类,那去掉 main.cpp 主程序引入的 student.h 文件不就可以了吗?这样确实可以避免重复引入 Student 类,但此方式并不适用于所有“重复引入”的场景。

C++ 多文件编程中,处理“多次 #include 导致重复引入”问题的方式有以下 3 种。

1) 使用宏定义避免重复引入

在实际多文件开发中,我们往往使用如下的宏定义来避免发生重复引入:

#ifndef _NAME_H
#define _NAME_H
//头文件内容
#endif

其中,_NAME_H 是宏的名称。需要注意的是,这里设置的宏名必须是独一无二的,不要和项目中其他宏的名称相同。

当程序中第一次 #include 该文件时,由于 _NAME_H 尚未定义,所以会定义 _NAME_H 并执行“头文件内容”部分的代码;当发生多次 #include 时,因为前面已经定义了 _NAME_H,所以不会再重复执行“头文件内容”部分的代码。

也就是说,我们可以将前面项目中的 student.h 文件做如下修改:

#ifndef _STUDENT_H
#define _STUDENT_H
class Student {
    //......
};
#endif

虽然该项目 main.cpp 文件中仍 #include 了 2 次 "student.h",但鉴于 _STUDENT_H 宏只能定义一次,所以 Student 类也仅会定义一次。再次执行该项目会发现,其可以正常执行。

2) 使用#pragma once避免重复引入

除了前面第一种最常用的方式之外,还可以使用 #pragma one 指令,将其附加到指定文件的最开头位置,则该文件就只会被 #include 一次。

我们知道,#ifndef 是通过定义独一无二的宏来避免重复引入的,这意味着每次引入头文件都要进行识别,所以效率不高。但考虑到 C 和 C++ 都支持宏定义,所以项目中使用 #ifndef 规避可能出现的“头文件重复引入”问题,不会影响项目的可移植性。

和 ifndef 相比,#pragma once 不涉及宏定义,当编译器遇到它时就会立刻知道当前文件只引入一次,所以效率很高。但值得一提的是,并不是每个版本的编译器都能识别 #pragma once 指令,一些较老版本的编译器就不支持该指令(执行时会发出警告,但编译会继续进行),即 #pragma once 指令的兼容性不是很好。

目前,几乎所有常见的编译器都支持 #pragma once 指令,甚至于 Visual Studio 2017 新建头文件时就会自带该指令。可以这么说,在 C/C++ 中,#pragma once 是一个非标准但却逐渐被很多编译器支持的指令。

除此之外,#pragma once 只能作用于某个具体的文件,而无法向 #ifndef 那样仅作用于指定的一段代码。

这里仍以前面的 "student.h" 文件为例,将其内容修改为:

#pragma once
class Student {
    //......
};

再次运行项目,同样可以正常执行。

3) 使用_Pragma操作符

C99 标准中新增加了一个和 #pragma 指令类似的 _Pragma 操作符,其可以看做是 #pragma 的增强版,不仅可以实现 #pragma 所有的功能,更重要的是,_Pragma 还能和宏搭配使用。

有关 _Pragma 操作符更多的功能和用法,本节不做详细讲解,这里仅介绍如何用 _Pragma 操作符避免头文件重复引入。

当处理头文件重复引入问题时,可以将如下语句添加到相应文件的开头:

_Pragma("once")

比如,将该语句添加到前面项目中 student.h 文件中的开头位置,再次执行项目,其可以正常执行。

事实上,无论是 C 语言还是 C++,为防止用户重复引入系统库文件,几乎所有库文件中都采用了以上 3 种结构中的一种,这也是为什么重复引入系统库文件编译器也不会报错的原因。

总结

本节介绍了 3 种避免头文件被重复引入的方法,其中 #pragma once 和 _Pragma("once") 可算作一类,其特点是编译效率高,但可移植性差(编译器不支持,会发出警告,但不会中断程序的执行);而 #ifndef 的特点是可移植性高,编译效率差。读者可根据实际情况,挑选最符合实际需要的解决方案。

除非对项目的编译效率有严格的要求,强烈推荐读者选用第一种解决方案,即采用 #ifndef / #define / #endif 组合解决头文件被重复引入。

另外在某些场景中,考虑到编译效率和可移植性,#pragma once 和 #ifndef 经常被结合使用来避免头文件被重复引入。比如说:

#pragma once
#ifndef _STUDENT_H
#define _STUDENT_H
class Student {
    //......
};
#endif

当编译器可以识别 #pragma once 时,则整个文件仅被编译一次;反之,即便编译器不识别 #pragma once 指令,此时仍有 #ifndef 在发挥作用。

知识点滴 - 关于头文件的重复包含问题 对于函数声明来说,如果一个编译单元里出现多次相同的声明没有问题,但如果是一个编译单元里对同一个对象(变量)或类型有多个定义,或者是同一个作用域里有重复定义,比如全局空间有重复定义,就会编译报错。重复包含一个头文件,可能会导致编译错误,就算头文件中都是可以重复出现的声明之类的内容,多次包含的话,也会增加预处理器或编译器的工作量,增加软件构建的时间。在一个源文件中包含此头文件my_include.h时,会检查此宏定义是否定义,如果是第一次包含,没有定义,则下一步定义这个宏,并将后面的内容包含进来。 阅读详情

相关推荐

C/C++开发中防止头文件被重复引入的3种方法

我们在用 C 语言开发软件时,经常使用宏定义(#ifndef / #define / #endif)来有效避免头文件被重复 #include,此方式在 C++ 多文件编程中也很常用。 举个例子,如下是一个 C++ 项目,其内部含有 school.h 和 student.h 这 2 个头文件以及 main.cpp 源文件,其各自包含的代码为: //student.h class Student { //...... }; //school.h #include "student...

Qsir的专栏 2274

如何防止头文件被重复包含或引用?

一、#pragma once ( 比较常用) 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用。 #pragmaonce是编译相关,就是说这个编译系统上能用,但在其他编译系统不一定可以,也就是说移植性差,不过现在基本上已经是每个编译器都有这个定义了。 #pragmaonce这种方式,是微软编译器独有的,也是后来才

Sharp_UP的博客 2万+

C 语言中防止头文件重复包含的机制

例如,假设有一个函数声明在头文件中,并且该头文件在多个源文件中都被包含。如果没有防止重复包含的机制,就会出现重复定义错误。void foo();// 函数声明如果没有防止重复包含,编译器会认为foo被多次定义,导致链接错误。使用#ifndef#define和#endif:这种方法是标准的 C 语言做法,可以有效避免头文件重复包含,广泛适用于不同的编译器和平台。使用:这种方法语法简洁,适用于大多数现代编译器,但它是编译器特有的扩展,可能不兼容某些旧版编译器。

m0_62599305的博客 1268

【C++】C++中防止头文件重复包含的两种方法

文章目录01、错误分析:类型重定义(头文件重复包含)02、解决方案2.1、微软宏2.2、条件编译2.3、两种方法比较03、变量被重复包含3.1、解决办法04、版权声明&总结 01、错误分析:类型重定义(头文件重复包含) 现象: #include文件的一 个不利之处在于一个头文件可能会被多次包含,为了说明这种错误,考虑下面的代码: #include "Index.h" #include "Index.h" //当前实际开发中没人会这么写程序,但是我们换一种写法 常犯错误如下: //#inclu

Cain Xcy的博客 6838

C++防止头文件被重复引入的3种方法!

在之前我们详细介绍了 C 语言中如何使用宏定义(#ifndef / #define / #endif)来有效避免头文件被重复 #include,此方式在 C++ 多文件编程中也很常用。 举个例子,如下是一个 C++ 项目,其内部含有 school.h 和 student.h 这 2 个头文件以及 main.cpp 源文件,其各自包含的代码为: //student.h class Student { //...... }; //school.h #include "student.h" class S

编程与实战的博客 1476

codemirror6 制作markdown编辑器(源码模式)

总体上感觉能用,但是不怎么友好,官方文档有点散乱,而且关键字高亮功能是独立出去的,去官方文档找半天,也没找到怎么改。EditorView.theme可以往EditorView模块中修改CSS的样式,从而影响编辑器的样式展示。"### 测试\n\n```javascript\nlet x = 'y'\n```"这个插件中的markdown语法的高亮样式。//这里指定markdown中代码块使用的解析扩展。开头的class样式,并且还需要在选择器前面添加。//markdown语言解析扩展。

qq_43203949的博客 1782

避免头文件重复引入和重复定义

1 将声明和实现分开   在*.c文件中实现,在*.h 中声明。包括函数,自定义数据结构等。如: *.c #include"*.h" //头文件应全部在对应的*.h中引入,`*.c`文件只需引入对应的`*.h`文件即可 int c[10]={0}; int Add(int a, int b) { return a+b; } *.h #pragma...

liao20081228的博客 1万+

Windows Server 2012 R2虚拟机安装全攻略:从镜像选择到网络配置一步到位

本文提供Windows Server 2012 R2虚拟机安装全攻略,涵盖从镜像选择到网络配置的完整流程。详细讲解在Oracle VM VirtualBox中的安装步骤、TCP/IP网络设置、系统优化及常见问题解决方案,帮助用户快速搭建可立即投入使用的服务器环境。特别适合IT初学者和系统管理员学习传统服务器应用的部署与配置。

weixin_28363123的博客 537

在C/C++中防止头文件重复包含的几种方式

在 C/C++ 编程中,头文件的重复包含会导致一系列的问题,如符号重定义、编译错误等。因此,防止头文件的重复包含是至关重要的。下面是几种常见的防止头文件重复包含的方式,并对其做了相关分析和使用建议。 博主在实际开发中一般采用第一种宏定义防护来规避头文件重复包含问题。

crr411422的博客 4610

Node-Red系列教程——NodeRed通过OPC UA读取数据并写入mysql

NodeRed通opcua读取西门子数据并存入mysql

鲸鱼姐的专栏 1万+

用Python实现四叉树(quad tree)

import numpy as np #正方形类 class square: #lx、ly为左上角坐标(x对应行号,y对应列号),rx、ry为右下角坐标 def __init__(self,lx,ly,rx,ry): self.lx=lx self.ly=ly self.rx=rx self.ry=ry #检查该矩阵中是否满足条件 #参数:原矩阵,阈值 #返回值:布尔类型 def check(s

weixin_44164489的博客 5868

防止C语言头文件被重复包含

文章目录方法一:使用宏保护防止C语言头文件被重复包含 (很常用)方法二: #pragma once(在头文件的最开始加入) ( 比较常用) 参考链接: https://blog.youkuaiyun.com/m0_37624078/article/details/81911808 方法一:使用宏保护防止C语言头文件被重复包含 (很常用) 当1个C语言程序由 多个 源程序文件 组成时,由于每个 源程序文件 都有 #include <…> #include “…h”, 最终它们可能形成交叉 包含 和 重复包

博雅勇士的博客 9199

双目视觉入门实战:用Matlab标定相机,再到Python OpenCV完成测距的完整链路

本文详细介绍了双目视觉技术的完整实现流程,从Matlab相机标定到Python OpenCV测距的全链路实践。重点解析了Matlab与OpenCV的参数转换技巧,以及立体校正、视差计算等关键步骤的代码实现,帮助开发者快速掌握双目测距系统的搭建方法。

weixin_29166013的博客 444

防止头文件被重复引用

一、下划线“__”属于编程风格的内容,对程序没有影响。不用下划线也可以,用几个下划线也由个人习惯。 二、其实质是一个宏名。由此我们可以防止发生重复定义或声明。 假设你的头文件名为head.h,根据习惯,我们声明一个宏HEAD_H,对应这个头文件,在头文件中开始的地方和结尾的地方加上   对HEAD_H的声明和判断,头文件Head.h如下:  #ifndef   HEAD_H

qq1987924的专栏 1万+

PWM调节DCDC参数计算原理

SOC芯片的核电压、GPU电压、NPU电压、GPU电压等,都会根据性能和实际应用场景来进行电压和频率的调整。 即动态电压频率调整DVFS(Dynamic Voltage and Frequency scaling),优化性能和功耗。

电子绿洲的博客 3158

特征提取 Features Extraction

介绍了特征提取的基本概念,从分类变量,文本信息和图片信息中进行特征提取的方法,以及实现特征提取的类库

JasonH2021的博客 1万+

C++ - 头文件基础(常用标准库头文件、自定义头文件、头文件引入方式、防止头文件重复包含机制)

C++ - 头文件基础(常用标准库头文件、自定义头文件、头文件引入方式、防止头文件重复包含机制)

weixin_52173250的博客 1458

HTML音乐爱心3D旋转相册完整源码

HTML音乐爱心3D旋转相册完整源码

LilyCoder的博客 1379

如何防止头文件被重复包含

为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifndef方式,一种是#pragma once方式。在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。 方式一: #ifndef__SOMEFILE_H__ //或写为#if!define__SOMEFILE_H__ #define__SOMEFILE_...

weixin_41066529的博客 4191

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

防止头文件重复包含的两种方法及区别

1.条件编译语句#ifndef#define#endif 相信很多人都知道第一种方法。#ifndef _TEST_H_ //——1 #define _TEST_H_ //——2 //加入各种变量,函数声明 #endif //——3以上代码:如果没有定义TEST_H变量,就继续往下执行,如果定义了,就直接endif,即不做任何操作。 如果一个文件中包含

lixungogogo的博客 1万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

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

的优势:简洁: 一行代码搞定。不易出错: 无需发明唯一宏名,避免命名冲突。通常更快: 编译器优化更直接。处理链接文件更可靠: 对同一物理文件的不同路径包含更安全。文件宏守卫的优势:标准合规: 100% 符合 C/C++ 标准。最大可移植性: 适用于任何符合标准的编译器(包括非常古老的或嵌入式编译器)。对文件副本更明确: 物理副本需要不同的宏名(这是应该的),行为更直观(虽然宏名冲突是问题)。最佳实践 (现代 C/C++ 开发):优先使用。

YZJincsdn的博客 1441

两种防止头文件重复引入的方法的区别

C/C++在预处理的时候,include相同的文件,预处理器会检查XXX是否有定义再决定要不要复制内容,重复包含会是编译器多检查几次而已。另外在使用增量编译的时候,这个文件变化,所有 include 这个文件的文件都需要重新编译,即使没有去使用里面的任何内容,所以重复包含最经常带来的错误就是重定义。 在用VC6.0向导生成的头文件中,经常可以看见如下的代码段:   #if

Sevenupcsdn的博客 757

C/C++避免头文件重复包含的方法

C/C++避免头文件重复包含的方法1. #ifndef2. #pragma once3. 混合使用 在实际的编程过程中,因为会使用多个文件,所以在文件中不可避免的要引入一些头文件,这样就可能会出现一个头文件被 include 多次,在C/C++中有几种不同的方式可以解决这个问题,总体功能相差不大,但依然存在细微差别。 1. #ifndef 格式如下: #ifndef __COMPLEX__ #de...

九霄星河的博客 9228
上一篇: 2021-03-09
下一篇: C/C++程序编译过程详解
令羽飞飞
博客等级 码龄14年 42粉丝 166原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值