在C++文件中我们常常看到文件中有#ifndef… #def…#endif (或者#ifdef … #def…)这些代码,它们属于预处理中的条件编译,主要有以下两个作用,防止头文件被重复引用和按条件对代码进行编译或者不编译。
1.防止头文件被重复引用
C++在预处理阶段会处理#include预编译指令,将被包含的头文件插入到该预编译指令所在的位置,该过程是递归进行的,包含的文件可能还包含其他文件。
一般防止头文件重复引用会有如下的格式:
#ifndef _X_H //如果没有包含x.h头文件
#define _X_H //则引入x.h头文件,并执行以下的函数代码
/*code*/ //代码段
#endif //结束标志
举例如下:如果有头文件a.h包含了头文件c.h,并且c.h中只有变量num的声明,那么当main.cpp同时包含头文件a.h和c.h时,执行下main.cpp时,会发生变量重复定义的错误:
//file a.h
#include "c.h"
//file c.h
int num;
//file main.cpp
#include <iostream>
#include "a.h"
#include "c.h"
using namespace std;
int main()
{
num=5;
cout<<num<<endl;//报错,num重复定义。
}
报错截图如下:
解决这个问题可以加入条件编译处理,只要在头文件c.h中加入以下三行即可,就不会产生变量的重复定义。
//file c.h
#ifndef _C_H //如果没有包含c.h头文件
#define _C_H //则引入c.h头文件,并执行以下的函数代码
int num; //代码段
#endif //结束标志
原因是main.cpp在处理第一行预处理语句#include “a.h”时首先会展开头文件a.h,由于a.h包含了头文件c.h,此时迭代引入头文件c.h,由于此时是第一次包含c.h,会执行c.h中的int num语句,声明变量num;接着处理第二行预处理语句#include “c.h”,由于此时已经包含了头文件c.h,就不会执行int num语句,因此不会发生重定义的错误。
2.按条件对代码进行编译或者不编译
除了防止头文件重复包含这一功能之外,还可以进行有条件的编译部分代码,代码格式如下,主要有两种例子:
#ifndef XXX //如果没有宏定义XXX,则执行代码
/*code*/
#endif
#ifdef XXX //如果宏定义了XXX,则执行代码
/*code*/
#endif
下面是一个具体的例子,我们可以利用条件编译对代码进行debug,输出想要的内容或者忽略部分代码,实际项目中,经常利用条件编译实现特定的代码模块的功能。
#include <iostream>
#define DEBUG1
#define DEBUG2
using namespace std;
int main()
{
#ifndef DEBUG1//如果没有定义 DEBUG1,则执行以下代码
cout<<"NOT DEBUG1"<<endl;//代码不满足条件编译的条件,不进行编译
#endif
#ifdef DEBUG2//如果定义了 DEBUG2,则执行以下代码
cout<<"DEBUG2"<<endl;
#endif
#ifdef DEBUG1//如果定义了 DEBUG1,则执行以下代码
cout<<"DEBUG1"<<endl;
#endif
}
因为定义了DEBUG2和DEBUG1,程序会忽略第一个条件编译,编译最后两个条件编译语句,输出DEBUG2和DEBUG1,输出截图如下:
|