摘要:总结了条件编译和if else的区别,#include在包含头文件时候的注意点,使用条件编译避免重复包含头文件,最后给出一个实例加深理解。
一、什么是条件编译
我们在移植u-boot和linux内核的时候,经常会看到#ifdef…#endif或者#ifndef…#endif这样的代码,这个就是条件编译,总的来说:
1.条件编译行为类似if…else,都是条件成立做什么事,不成立就不做什么事。
2.条件编译是作用在预处理阶段的指示命令,用于控制是否编译某段代码,这也是它和if..else不同的地方。
二、条件编译和if…else语句的区别
通俗的解释一下,就是条件编译在预处理阶段,根据#if后面的条件是否成立,来判断哪些代码会被编译进去,哪些不会编译,经过条件编译之后,我们的编译器是看不到那些不成立部分的代码的。而if。。else是要在程序运行的时候进行值的判断,编译器是要对if 和else两个部分的代码都要进行编译。举个例子如下:
#include<stdio.h>
#define c 1
int main(void)
{
#if(c==1)
{
printf("happytiaojianbianyi!\n");
}
#else
{
printf("tiaojianbianyiis not happy!\n");
}
#endif
if(c==1)
{
printf("happyif else!\n");
}
else
{
printf("ifelse is not happy!\n");
}
return0;
}
接着,我们先生成预编译阶段的代码,在编译运行:
#gcc–E test1.c –o test1.i
得到的text1.i文件如下;
#2 "test1.c" 2
int main(void)
{
{
printf("happy tiaojianbianyi!\n");
}
if(1==1)
{
printf("happy if else!\n");
}
else
{
printf("if else is not happy!\n");
}
return 0;
}
红色字体是要注意的部分,可以很明显的看到,在预编译阶段,条件编译把不成立的部分直接去掉了,而if和else则被完全保留了下来,这就是最直接的差别,条件编译会根据不同的目标平台做改变,比如我们要移植mini2440的u-bot,那么我们就在相关文件里面#define MINI2440_CONFIG,这样我们在编译的时候就会大大的简化代码,接着编译运行:
#gcc test1.c –o test1
得到的结果如下:
#happytiaojianbianyi!
#happyif else!
结果都是可以预计的,但是过程是不同的。
三、编译阶段定义宏
刚才的例子,我们在文件的顶部加了一句
#definec 1
但是我们在编译的时候,想要看等于0的情况,如果每次都去修改代码会比较麻烦,这时候就可以借助编译器的功能,这时候我们把原来程序里面宏定义的部分给注释掉,如下:
//#definec 1
接着,按照如下方法编译:
#gcc –DC=0 test1.c –o test
这时候出现的结果就变成了如下:
#tiaojianbianyiis not happy!
#ifelse is not happy!
说明我们在编译的时候,指定的宏定义已经生效了。
四、#include的本质
1.include的本质是将已经存在的文件内容嵌入到当前文件中。这句话说明意思呢?就是说,比如我们在程序里面,直接使用了printf这个函数,这个函数我们没有定义啊,怎么来的呢?就是因为我们#include<stdio>这个头文件,这个头文件里面是标准的输入输出文件,里面已经为我们写好了各种各样的输入输出函数,所以我们在预编译的时候,前面会有一大段,就是stdio里面的东西。
2.#include简介包含同样会产生嵌入文件的动作。比如,我们include”test.h”然后test.h里面又include”fun.h”,那么在我们的源文件里面就会把test.h和fun.h里面的内容都嵌入到我们的源文件里面去。这样就会引起什么问题呢?重复包含,重复包含一定是会报错的,试想一下你在一个文件里面两次定义一个函数,会不会报错,答案是肯定的。
五、条件编译解决include重复包含头文件
其实原理很简单,就是在文件头加上两句话,意思是,如果我已经包含了某某头文件,那么久不要再包含了,举个例子:
我们有三个文件;test2.c,test2.h和fun.h
分别如下:
test2.c
#include <stdio.h>
#include "test2.h"
#include "fun.h"
int main(void)
{
printf("%d\n",fun(2,3));
return0;
}
test2.h
#include"fun.h"
fun.h
#ifndef _FUN_H_
#define _FUN_H_
int fun(int a,int b)
{
returna+b;
}
#endif
文件很简单,红色字体是在重复添加头文件的时候需要加进去的,有时候我们可以直接去重复添加的头文件不就完了吗?但是在处理很大的项目的时候,我们并不能认为的保证我们添加的头文件或者函数没有被别的组定义,使用这个方法可以消除这个顾虑,这样就会判断我们是否已经包含了这个头文件,如果已经包含了,那就不在包含。
六、条件编译意义与总结
1.条件编译可以产生不同的目标代码,在预编译阶段被处理,而if..else在程序运行的时候在做判断。
2.条件编译可以用于不同的产品线共用一份代码,或者区分调试版和发布版。
3.条件编译可以避免重复包含同一个头文件。
这篇帖子就总结到这里,如有不正确的地方还请指出,大家共同进步!