1. 条件编译
由于C++兼容C语法,所以我们这里介绍的虽然是C的条件编译,但是在C++中也是这样的。
1.1 条件编译的作用
其实是从“条件编译”这个名字上就能看出,所谓“条件编译”其实就是“按照条件去编译”。
也就是“预编译”时,预编译器处理“条件编译”时,可以通过“条件编译”帮你保留某些代码、以及帮你去掉某些代码,第二阶段编译时就只编译保留的代码。
一般情况下,C源程序中的每一行代码都要参加编译的,但有时候出于对程序代码优化的考虑、或者其它方面的考虑,我们只希望对其中一部分内容进行编译,此时就需要在程序中加上条件(条件编译),让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃。
a.c
#include <stdio.h> #define NUM1 int main(void) { int a = 0; #ifdef NUM1 a += 10; #endif #ifdef NUM2 a += 1000; #endif }
比如以上这个a.c,预编译器在对a.c进行预编译时,由于只定义了NUM1宏,没有定义NUM2宏,所以预编译后,main函数中只留下了int a += 10;。
预编译后,main函数最后就变为了如下样子:
int main(void) { int a = 0; int a += 10; }
如此就实现了代码的选择。
1.2 C初学者对条件编译的误解
对于很多C的初学同学来说,往往误认为条件编译可有可无,它是一个不重要的东西。
(1)误解的原因
1)初学C语言时,写的练习程序都太简单了,几乎用不到。
2)初学时很少阅读复杂C源码,很难接触别人写的包含大量条件编译的代码很少阅读的原因,一个是因为没有工作环境的支持,你阅读不到,第二个就算接触到了,你也根本看不懂。
(2)除了复杂宏定义外,其实条件编译也是阻碍我们阅读复杂C源码的难关之一。
在复杂的C代码中,往往到处都充满了条件编译这个东西,如果你搞不定条件编译,你很难读懂复杂的C代码,但是在实际与c相关的开发中,阅读复杂的OS、库、驱动、框架代码确又是家常便饭的事情。
1.3 为什么条件编译在实际开发中这么重要
因为实际开发的C程序,往往因为各种原因,需要在同一个程序中编写出针对不同情况(比如不同OS、硬件环境)的代码,编译程序时为了编译得到针对不同情况的可执行程序,我们需要使用条件编译来做选择。
当然程序中并不是所有的代码都需要使用条件编译来选择,只有哪些需要被选择的代码,我们才会对其使用条件编译。
疑问:为什么不直接全部编译呢?
这样子会导致我们的可执行程序非常大,因为里面不仅包含了我们需要的代码,还包含了很多用不到的代码。
但是使用条件编译将不需要的代码去掉后,就不存在这样的情况了。
程序变小之后,程序不管是静态存储在硬盘上,还是运行在内存中时,将会非常节省计算机的硬盘空间和内存空间。
特别是当你的程序非常庞大时,又或者是当你的计算机资源本来就不是很足时,这一点就显得更重要了。
1.4 什么情况下需要使用条件编译
(1)文件内容被重复include时,去掉重包含的内容
(2)实现程序的跨平台
(3)辅助调试程序
有关这三种情况,我们后面再详细说。
1.5 常见的条件编译有哪些,基本用法是怎样的
1.5.1 条件编译种类概述
(1)对于条件编译,关键是理解而不是死记硬背
只要你理解了,就算忘了怎么写了,上网上一查便知。
(2)条件编译种类
条件编译主要有两种:
1)第一种:#ifdef、#ifndef
(a)ifdef:if defined的缩写
(b)ifndef:if ndefined的缩写
由于#ifndef的功能与#ifdef刚好相反,所以只要理解了#ifdef,就一定能理解#ifndef。
为了面对更复杂的情况,#ifdef、#ifndef往往还会和#else的搭配。
2)第二种:#if
为了得到更复杂的用途,#if往往会和defined、#elif、#else的搭配。
#elif:else if的缩写,类似c语法中的else if
(3)注意
1)不管那种情况,结尾时都是必须使用#endif结尾,这是固定格式。
#ifdef *** ... #endif
#if *** ... #endif
#endif表示结束该条件编译。
#ifdef、#if 好比{
#endif 好比}
必须配对使用。
2)条件编译所包含的可以是任何内容
你需要对什么进行条件编译,条件编译就可以包含什么内容,这个是根据你自己需求来定的。
(a)可以是
#include <***> #ifdef *** #include <****.h> #include <****.h> ... #endif
(b)整函数
#ifndef *** int fun(int a, int b) { ... } #endif
(c)函数内部的部分代码
int fun(int a) { #if *** int b = 100; ... #else ... #endif ... ... ... }
(d)类型定义,变量定义
#if *** struct student { #ifdef *** int num; ... #endif ... }; struct student stu; int gbl_va = 100; #endif
(e)整个文件的内容
stdio.h #ifndef _STDIO_H_ ... ... //整个头文件的内容 #endif
3)#elif、#else、defined等,只能与#if #ifdef搭配使用,不能独立使用
(a)错误的写法
比如:
#elif *** ... #endif #else ... #endif
(b)正确写法
比如:
#if *** ... #elif ... #else ... #endif #ifdef *** ... #else ... #endif
为了简单期间,我们再给大家演示条件编译如何使用时,我们只在.c文件中演示,但是实际上在.h文件中,条件编译的使用是一样的,因为.h中的内容被包含到.c中后,其实还是变成了.c的一部分。