#ifndef 是"if not defined"的简写,是预处理功能(宏定义、文件包含、条件编译)当中的条件编译,可以根据是否已经定义了一个变量来进行分支选择,其作用是:

  1、防止头文件的重复包含和编译;

  2、便于程序的调试和移植;

  下面分别举例描述。

一、防止头文件的重复包含和编译

下面是错误示范:


headfile_1.h

 #include <iostream>
class CTest_1 {
CTest_1() {
//do something,eg:init;
}
~CTest_1() {
//do something ,eg:free;
}
void PrintScreen()
{
std::cout << "this is Class CTest_1!" << std::endl;
}
};

headfile_2.h

 #include "headfile_1.h"
class CTest_2 {
CTest_2() {
//do something,eg:init;
}
~CTest_2() {
//do something,eg:free;
}
void PrintScreen()
{
std::cout << "this is Class CTest_2!" << std::endl;
}
};

sourcefile.cpp

 #include <iostream>
#include "headfile_1.h"
#include "headfile_2.h" int main()
{
return ;
}

编译时提示重定义错误:


  以上显示headfile_1.h中的类CTest_1重定义了。

  一般地,假如有一个C源文件(如sourcefile.cpp),它包含两个头文件(如headfile_1.h和headfile_2.h),而头文件headfile_2.h又包含了headfile_1.h,则最终的效果是该源文件包含了两次headfile_1.h。如果你在头文件里定义了结构体或者类类型,那么问题来了,编译时将会报重复定义的错误。

  加上条件编译"ifndef"则问题可解决。在headfile_1.h中加上条件编译,如下:

headfile_1.h

 #ifndef _HEADFILE_1_H
#define _HEADFILE_1_H
#include <iostream>
class CTest_1 {
CTest_1() {
//do something,eg:init;
}
~CTest_1() {
//do something ,eg:free;
}
void PrintScreen()
{
std::cout << "this is Class CTest_1!" << std::endl;
}
}; #endif //end of _HEADFILE_1_H

编译通过!

  分析:当第一次包含headfile_1.h时,由于没有定义_HEADFILE_1_H,条件为真,这样就会执行#ifndef _HEADFILE_1_H和#endif之间的代码;当第二次包含headfile_1.h时,前面一次已经定义了_HEADFILE_1_H,条件为假,#ifndef _HEADFILE_1_H和#endif之间的代码也就不会再次被包含,这样就避免了重定义。

  

  小结:还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你最好都加上这个。一般格式是这样的:

#ifndef <标识>
#define <标识> ...... ...... #endif

  <标识>在理论上来说是可以自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的明明规则一般是头文件名全大写,前面加下划线,并把文件名中的"."也变成下划线,如:stdio.h

#ifndef _STDIO_H
#define _STDIO_H ...... ...... #endif

注意:#ifndef起到的效果是防止一个源文件多次包含同一个头文件,而不是防止两个源文件包含同一个头文件。事实上,防止同一头文件被两个不同的源文件包含这种要求本身就是不合理的,头文件存在的价值就是被不同的源文件包含。

  

二、便于程序的调试和移植

  在调试程序时,常常需要对程序中的内容进行选择性地编译,即可以根据一定的条件选择是否编译。

  主要分以下几种:

1、

#ifndef 标识符

程序段 

#else

程序段 

#endif

它的作用是当“标识符”没有由#define定义过,则编译“程序段1”,否则编译“程序段2”。

2、

#ifndef 标识符

#define 标识符

程序段 

#else

程序段 

#endif

它的作用是当“标识符”没有由#define定义过,则编译“程序段1”,否则编译“程序段2”。

3、

#if 表达式

程序段 

#else

程序段 

#endif

它的作用是当“表达式”值为真时,编译“程序段1”,否则编译“程序段2”。

注:以上三种形式中#else不是强制的,可省略;当然,当#else后需要嵌套#if时,可以使用预处理命令#elif,它相当于#else#if。

小结:在程序中使用条件编译主要是为了方便程序的调试和移植。

#ifndef详解的更多相关文章

  1. #ifndef HeaderName_h #define HeaderName_h #endif 使用详解(转)

    原文:#ifndef HeaderName_h #define HeaderName_h #endif 使用详解 想必很多人都看到过头文件中写有:#ifndef HeaderName_h       ...

  2. trie字典树详解及应用

    原文链接    http://www.cnblogs.com/freewater/archive/2012/09/11/2680480.html Trie树详解及其应用   一.知识简介        ...

  3. 【转载】C/C++中extern关键字详解

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  4. C++预处理详解

    本文在参考ISO/IEC 14882:2003和cppreference.com的C++ Preprocessor的基础上,对C++预处理做一个全面的总结讲解.如果没有特殊说明,所列内容均依据C++9 ...

  5. AFNetworking 与 UIKit+AFNetworking 详解

    资料来源 : http://github.ibireme.com/github/list/ios GitHub : 链接地址 简介 : A delightful iOS and OS X networ ...

  6. 转载:C/C++源代码到可执行程序的过程详解

    C/C++源代码到可执行程序的过程详解 编译,编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格 ...

  7. C++宏定义详解

    一.#define的基本用法     #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质 ...

  8. cppunit使用详解

    cppunit使用详解 第一步:如何安装 (我的运行环境: fc7 Linux, gcc4)    cppunit 的安装是相当标准的linux的安装过程    a. 下载cppunit的源文件    ...

  9. jni.h头文件详解二

    作者:左少华 博客:http://blog.csdn.net/shaohuazuo/article/details/42932813 转载请注明出处:http://blog.csdn.net/shao ...

随机推荐

  1. bzoj4817/luogu3703 树点涂色 (LCT+dfs序+线段树)

    我们发现,这个染色的操作他就很像LCT中access的操作(为什么??),然后就自然而然地想到,其实一个某条路径上的颜色数量,就是我们做一个只有access操作的LCT,这条路径经过的splay的数量 ...

  2. luogu1377 树的序 (线段树)

    题意:给你一个1~N的排列,然后让你按顺序把它们插到一个二叉搜索树里,然后问能插出同样的二叉搜索树的 字典序最小的排列是什么 本来可以直接模拟建树然后dfs一下输出结果...然而有可能会退化成链,最差 ...

  3. 【bzoj1507】 JSOI2008—Blue Mary的旅行

    http://www.lydsy.com/JudgeOnline/problem.php?id=1570 (题目链接) 题意 给出$m$个航班,每天只能做一次飞机,有$T$人从起点到终点,问最晚到达的 ...

  4. 在kubernetes集群上用helm安装Datadog(Monitoring)

    Datadog is a monitoring service that gathers monitoring data from your containers within your Azure ...

  5. xor定理证明

    xor 证明: 0 xor 0=0 0 xor 1=1 1 xor 0=1 1 xor 1=0 0 xor 其它数,数值不会改变1 xor 其它数,数值会反转 所以x个数0和y个数1进行xor运算(0 ...

  6. SIFT特征点检测学习一(转载)

    新手上路,先转载学习tornadomeet的博客:http://www.cnblogs.com/tornadomeet/archive/2012/08/16/2643168.html 特征点检测学习_ ...

  7. 【bzoj5161】最长上升子序列 状压dp+打表

    题目描述 现在有一个长度为n的随机排列,求它的最长上升子序列长度的期望. 为了避免精度误差,你只需要输出答案模998244353的余数. 输入 输入只包含一个正整数n.N<=28 输出 输出只包 ...

  8. Iptables防火墙规则使用

    iptables是组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火墙解决方案,完成封包过滤.封包重定向和网络地址转换(NAT)等功能 ...

  9. 门店评级VS坏客户

    sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...

  10. JVM调优命令-jstack

    jstack jstack用于生成java虚拟机当前时刻的线程快照.线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁 ...