c++条件编译详解
c++条件编译详解
本篇文章专注于解答在《c++预处理器》一文中提出的问题,并进一步提升对c++条件编译的认识。
通常,源文件中所有内容都要参加编译,但是在某些时候,可能希望源文件中某些部分在满足某些条件的情况下才进行编译,这就是所谓的条件编译。
有趣的是,对于c++的初学者来说,没有条件编译照样可以写出可以良好运行的程序,所以条件编译的知识常常会被忽视。
但事实上,条件编译非常有用。要注意,对于一些小型的程序,条件编译的作用可能常常被掩盖,但是当程序的规模变大后条件编译的作用和优势就会显现出来了。因此把握它还是非常重要的。
条件编译的形式
条件编译有以下三种形式:
形式一
#ifdef 标识符
程序片段1
#else
程序片段2
#endif
上述语句的意思就是如果标识符已被#define命令定义过,则对程序片段1进行编译;否则对程序片段2进行编译。其中,程序片段2可以为一个空的程序段,那么#else就没有什么实际的意义了,这时可以将其省略。
请看下面看这段示例代码。
#include <iostream>
#define DEBUG
using namespace std;
void main()
{
#ifdef DEBUG
cout << "Begin..." << endl;
#else
cout << "Cannot Begin!" << endl;
#endif
int array[10];
for(int i = 0;i < 10;i++)
{
array[i] = i;
#ifdef DEBUG
cerr << "i = " << i << endl;
cerr << "array[i] = " << array[i] << endl;
#endif
}
}
形式二
#ifndef 标识符
程序片段1
#else
程序片段2
#endif
形式2和形式1的区别在于#ifdef关键字换成了#ifndef关键字,其功能是如果标识符未被
define命令定义过,则对程序片段1进行编译;否则对程序片段2进行编译,这与形式1的
功能正好相反。
形式三
#if 标识符
程序片段1
#else
程序片段2
#endif
该形式完成的功能是如果表达式的值为真,则对程序片段1进行编译;否则对程序片段2
进行编译。因此可以使程序在不同条件下完成不同的功能。
条件编译的使用场景
1、避免头文件重复包含和变量重复定义
在c或c++中,头文件重复包含问题是程序员必须避免的问题,也是很多新手容易犯错的问题。
请读者先先思考这样一段代码:(方便起见将三个文件的代码写在一起)
//a.h
#include<stdio.h>
int A=1;
//b.h
#include "a.h"
void f(){printf("%d",A);}
//main.c
#include<stdio.h>
#include"a.h"
#include"b.h"
void main(){f();}
编译运行此程序会报错,提示你int A 被重复定义。
为什么会出现这样的问题呢,我们要从头文件的编译预处理说起。
我们知道在编译c或c++程序时候,编译器首先要对程序进行预处理,预处理其中一项工作便是将你源程序中#include的头文件完整的展开
于是乎,当出现头文件重复包含时,就会带来两种不利影响:
1、编译器编译步骤多次编译该头文件,工程代码量小还好,工程量一大会使整个项目编译速度变的缓慢,后期的维护修改变得困难。
2、头文件里对变量的多次定义会使程序在编译链接的时候崩溃。
解决:
头文件重复包含和变量重复定义可以借由条件编译解决,代码如下:
//a.h
#ifndef _A_H
#define _A_H
int A = 1;
#endif;
通过条件编译,实现了a.h只编译一次。
此外,微软的vs和vscode还提供了#pragma one预编译指令,其作用与条件编译相同。
//a.h
#pragma once
#include<stdio.h>
int A = 1;
2、交叉功能的项目文件
一些客户需要你这个产品里的功能A而另外一些客户不需要A,那么你就可以使用条件编译把实现A的所有代码包起来,这样你就可以#define和#undef来enable或者disable你的功能A了
3、便于文件调试
在形式一的样例代码中展现过这样的思路,即将调试过程中的附加代码用#ifdef DEBUG包起来,在预编译指令中通过加入与删除#define DEBUG来实现调试过程与最终代码之间的切换。

浙公网安备 33010602011771号