ifndef/define/endif——主要目的是防止头文件的重复包含和编译
原文:http://www.jb51.net/article/100939.htm
原文:https://blog.csdn.net/abc5382334/article/details/18052757
ifndef/define/endif”主要目的是防止头文件的重复包含和编译
想必很多人都看过“头文件中的 #ifndef/#define/#endif 防止该头文件被重复引用”。但是是否能理解“被重复引用”是什么意思?是不能在不同的两个文件中使用include来包含这个头文件吗?如果头文件被重复引用了,会产生什么后果?是不是所有的头文件中都要加入#ifndef/#define/#endif 这些代码?
其实“被重复引用”是指一个头文件在同一个cpp文件中被include了多次,这种错误常常是由于include嵌套造成的。比如:存在a.h文件#include "c.h"而此时b.cpp文件导入了#include "a.h" 和#include "c.h"此时就会造成c.h重复引用。
头文件被重复引用引起的后果:
有些头文件重复引用只是增加了编译工作的工作量,不会引起太大的问题,仅仅是编译效率低一些,但是对于大工程而言编译效率低下那将是一件多么痛苦的事情。
有些头文件重复包含,会引起错误,比如在头文件中定义了全局变量(虽然这种方式不被推荐,但确实是C规范允许的)这种会引起重复定义。
是不是所有的头文件中都要加入#ifndef/#define/#endif 这些代码?
答案:不是一定要加,但是不管怎样,用#ifnde xxx #define xxx #endif或者其他方式避免头文件重复包含,只有好处没有坏处。个人觉得培养一个好的编程习惯是学习编程的一个重要分支。
下面给一个#ifndef/#define/#endif的格式:
#ifndef A_H意思是"if not define a.h" 如果不存在a.h
接着的语句应该#define A_H 就引入a.h//否则不需要引入
最后一句应该写#endif
这里“引入”就是编译#define A_H下面的代码
--------------------------------------------------------------------------------------------------
#ifndef GRAPHICS_H // 防止graphics.h被重复引用
#define GRAPHICS_H
#include <math.h> // 引用标准库的头文件
…
#include “header.h” // 引用非标准库的头文件
…
void Function1(…); // 全局函数声明
…
class Box // 类结构声明
{
…
};
#endif
--------------------------------------------------------------------------------------------------
========================================================
用法:
.h文件,如下:
#ifndef XX_H
#define XX_H
...
#endif
这样如果有两个地方都包含这个头文件,就不会出现两次包含的情况 。。
因为在第二次包含时 XX_H 已经有定义了,所以就不再 include了
-------------------------------------------------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#ifndef GRAPHICS_H // 防止graphics.h被重复引用
#define GRAPHICS_H
#include < math.h > // 引用标准库的头文件
…
#include “myheader.h” // 引用非标准库的头文件
…
void Function1(…); // 全局函数声明
…
class Box // 类结构声明
{
…
};
#endif
|
-----------------------------------------------------
那是指你建立多个文件时,多个文件里都包含这个头文件
-----------------------------------------------------
给你举个例子,再顺便分析一下:
假设你的工程里面有4个文件,分别是a.cpp,b.h,c.h,d.h
a.cpp的头部是:
#include "b.h "
#include "c.h "
b.h和c.h的头部都是:
#include "d.h "
而d.h里面有class D的定义。
这样一来,
编译器编译a.cpp的时候,先根据#include "b.h "去编译b.h这个问题,再根据b.h里面的#include "d.h ",去编译d.h的这个文件,这样就把d.h里面的class D编译了;
然后再根据a.cpp的第二句#include "c.h ",去编译c.h,最终还是会找到的d.h里面的class D,但是class D之前已经编译过了,所以就会报重定义错误。
加上ifndef/define/endif,就可以防止这种重定义错误。
--------------------------------------------------
-------------------------------------------------
举例
1.比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。 还是把头文件的内容都放在#ifndef和#endif中吧。
不管你的头文件会不会被多个文件引用,你都要加上这个。
一般格式是这样的:
#ifndef <标识>
#define <标识>
......
......
#endif <标识>
在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h
1
2
3
4
|
#ifndef _STDIO_H_
#define _STDIO_H_
......
#endif
|
2.在#ifndef中定义变量出现的问题(一般不定义在#ifndef中)。
#ifndef AAA
#define AAA
...
int i;
...
#endif
里面有一个变量定义在vc中链接时就出现了i重复定义的错误,而在c中成功编译。
原因:
(1).当你第一个使用这个头的.cpp文件生成.obj的时候,int i 在里面定义了当另外一个使用这个的.cpp再次[单独]生成.obj的时候,int i 又被定义然后两个obj被另外一个.cpp也include 这个头的,连接在一起,就会出现重复定义.
(2).把源程序文件扩展名改成.c后,VC按照C语言的语法对源程序进行编译,而不是C++。在C语言中,若是遇到多个int i,则自动认为其中一个是定义,其他的是声明。
(3).C语言和C++语言连接结果不同,可能(猜测)在进行编译的时候,C++语言将全局变量默认为强符号,所以连接出错。C语言则依照是否初始化进行强弱的判断的。
参考解决方法:
(1).把源程序文件扩展名改成.c。
(2).推荐解决方案: .h中只声明 extern int i;
在.cpp中定义
#ifndef __X_H__
#define __X_H__
extern int i;
#endif //__X_H__ int i;
注意问题:变量一般不要定义在.h文件中。
ifndef/define/endif——主要目的是防止头文件的重复包含和编译相关推荐
- 防止头文件的重复包含
防止头文件重复包含的宏想必大家都清楚,#ifndef#define#endif就是干这个用的,面试中也考过.我也是知道这个宏的作用,今天我们就来实战测试一下,网上说的那是别人的东西,只有自己测试过出结 ...
- C语言头文件避免重复包含
C语言头文件避免重复包含 假定有以下几个头文件及其包含关系为: File1.h,file2.h,file3.h,file4.h,file5.h,main.cpp 那么:file3.h包含file1.h ...
- 如何防止头文件被重复包含或引用?
一.#pragma once ( 比较常用) 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用. #pragmaonce ...
- 如何防止头文件被重复包含、嵌套包含
[转自] http://hi.baidu.com/zengzhaonong/blog/item/8a8871062d481f7f03088106.html #include文件的一个不利之处在于一个头 ...
- 如何避免头文件被重复包含?
在实际的工程中我们很有可能重复包含某一个头文件,比如下面这种情况: 开发人员B和开发人员C在自己的头文件中都包含了开发人员A的头文件,而开发人员D在自己的编译单元中包含了B和C的头文件,此时D就相当于 ...
- C++ ifndef /define/ endif 作用和用法
ifndef/define/endif"主要目的是防止头文件的重复包含和编译 比如你有两个C文件,这两个C文件都include了同一个头文件.而编译时,这两个C文件要一同编译成一个可运行文件 ...
- #ifndef, #define, #endif的作用
目录 作用 示例 作用 #ifndef 它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义.文件包含.条件编译)中的一种--条件编译. 在c语言中, ...
- #ifndef, #define, #endif 作用
目录 #ifndef, #define, #endif 作用 #ifndef #ifdef #define #ifndef, #define, #endif 作用 #ifndef 它是if not d ...
- ifndef/define/endif的使用
ifndef/define/endif:简而言之就是避免头文件被重复引用. (ifdef/define/endif是已定义的宏为真,ifndef/define/endif是未定义的宏为真) 在一个大型 ...
最新文章
- MySQL 查询统计 日期查询
- 创建python2与python3虚拟环境失败的原因
- 第16课:项目实战——利用 PyTorch 构建 CNN 模型
- 误删/etc/passwd的修复
- 41.选项卡插件——tabs
- StartActivityForResult
- LeetCode 1599. 经营摩天轮的最大利润(模拟)
- dsm php,docker dsm是什么?
- c6011取消对null指针的引用_COM编程攻略(二十二 IDL中的枚举,指针,数组)
- C# ashx生成的验证码
- WordPress SEO 技巧
- 27岁研究生毕业年龄大吗?
- 抖音网红追女生小程序代码
- 蚂蚁调度AntJob-分布式任务调度系统
- idea配置查看代码汇编指令插件
- c++封装so库,供安卓android调用
- 恢复系统映像时错误代码0X80070057的解决方案
- 短视频如何做好引流与推广,分享四个快速涨粉方案
- java中前加加和后加加的案例
- 使用 SLF4J 进行高效的日志记录(@slf4j 注解)
热门文章
- 公路修建问题(二分+最小生成树)
- sys.stdout.write与sys.sterr.write(二)
- 不安装Oracle使用cx_Oracle
- Object-C代码练习【自定义对象的归档】
- Java Swing 树状组件JTree的使用方法【图】
- ASP与ASP.NET的区别
- freetype和libiconv编译
- html css发展前景,网页设计的发展趋势
- Python实用小工具了解一下,总有一款是你需要的
- 蓝桥杯四平方和Java_蓝桥杯 四平方和