原文: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——主要目的是防止头文件的重复包含和编译相关推荐

  1. 防止头文件的重复包含

    防止头文件重复包含的宏想必大家都清楚,#ifndef#define#endif就是干这个用的,面试中也考过.我也是知道这个宏的作用,今天我们就来实战测试一下,网上说的那是别人的东西,只有自己测试过出结 ...

  2. C语言头文件避免重复包含

    C语言头文件避免重复包含 假定有以下几个头文件及其包含关系为: File1.h,file2.h,file3.h,file4.h,file5.h,main.cpp 那么:file3.h包含file1.h ...

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

    一.#pragma once ( 比较常用) 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用. #pragmaonce ...

  4. 如何防止头文件被重复包含、嵌套包含

    [转自] http://hi.baidu.com/zengzhaonong/blog/item/8a8871062d481f7f03088106.html #include文件的一个不利之处在于一个头 ...

  5. 如何避免头文件被重复包含?

    在实际的工程中我们很有可能重复包含某一个头文件,比如下面这种情况: 开发人员B和开发人员C在自己的头文件中都包含了开发人员A的头文件,而开发人员D在自己的编译单元中包含了B和C的头文件,此时D就相当于 ...

  6. C++ ifndef /define/ endif 作用和用法

    ifndef/define/endif"主要目的是防止头文件的重复包含和编译 比如你有两个C文件,这两个C文件都include了同一个头文件.而编译时,这两个C文件要一同编译成一个可运行文件 ...

  7. #ifndef, #define, #endif的作用

    目录 作用 示例 作用 #ifndef 它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义.文件包含.条件编译)中的一种--条件编译. 在c语言中, ...

  8. #ifndef, #define, #endif 作用

    目录 #ifndef, #define, #endif 作用 #ifndef #ifdef #define #ifndef, #define, #endif 作用 #ifndef 它是if not d ...

  9. ifndef/define/endif的使用

    ifndef/define/endif:简而言之就是避免头文件被重复引用. (ifdef/define/endif是已定义的宏为真,ifndef/define/endif是未定义的宏为真) 在一个大型 ...

最新文章

  1. MySQL 查询统计 日期查询
  2. 创建python2与python3虚拟环境失败的原因
  3. 第16课:项目实战——利用 PyTorch 构建 CNN 模型
  4. 误删/etc/passwd的修复
  5. 41.选项卡插件——tabs
  6. StartActivityForResult
  7. LeetCode 1599. 经营摩天轮的最大利润(模拟)
  8. dsm php,docker dsm是什么?
  9. c6011取消对null指针的引用_COM编程攻略(二十二 IDL中的枚举,指针,数组)
  10. C# ashx生成的验证码
  11. WordPress SEO 技巧
  12. 27岁研究生毕业年龄大吗?
  13. 抖音网红追女生小程序代码
  14. 蚂蚁调度AntJob-分布式任务调度系统
  15. idea配置查看代码汇编指令插件
  16. c++封装so库,供安卓android调用
  17. 恢复系统映像时错误代码0X80070057的解决方案
  18. 短视频如何做好引流与推广,分享四个快速涨粉方案
  19. java中前加加和后加加的案例
  20. 使用 SLF4J 进行高效的日志记录(@slf4j 注解)

热门文章

  1. 公路修建问题(二分+最小生成树)
  2. sys.stdout.write与sys.sterr.write(二)
  3. 不安装Oracle使用cx_Oracle
  4. Object-C代码练习【自定义对象的归档】
  5. Java Swing 树状组件JTree的使用方法【图】
  6. ASP与ASP.NET的区别
  7. freetype和libiconv编译
  8. html css发展前景,网页设计的发展趋势
  9. Python实用小工具了解一下,总有一款是你需要的
  10. 蓝桥杯四平方和Java_蓝桥杯 四平方和