--事物的难度远远低于对事物的恐惧!
最近出差较多,没什么时间记录博客笔记,刚好乘五一假期好好写一点。今天我们来看看C语言条件编译使用分析。
在C语言中,我们很熟悉if...else...这样的条件语句,而我们这章所说的条件编译指令#if...#else...(当然条件编译指令还有#ifndef、#ifdef等等)很类似if...else...条件语句,那么他们二者有什么区别?我们先来分别用预处理器处理下边一段代码。
#define FLAG 1
int main()
{
char *p1 = "";
char *p2 = "";
//使用条件编译指令
#if(1 == FLAG)
p = "FLAG is Defined!";
#else
p = "FLAG is not Defined";
#endif
//普通if...else...语句
if(1 == FLAG)
p2 = "FLAG is Defined!";
else
p2 = "FLAG is not Defined";
return 0;
}
预处理器处理后的结果如下:
#line 1 "main.c"
int main()
{
char *p1 = "";
char *p2 = "";
p1 = "FLAG is Defined!";
#line 16 "main.c"
if(1 == 1)
p2 = "FLAG is Defined!";
else
p2 = "FLAG is not Defined";
return 0;
}
从预处理后的结果我们知道:被条件编译指令修饰的不符合条件的代码,已经被预处理器去掉了。
其实本质来说,条件编译就是预处理指示命令,用于控制是否否编译某段代码。
上段代码中,预处理指示命令就把 p1 = "FLAG is not Defined"这段代码给去掉了,使得编译器不对其进行编译;而普通的if...else...语句,则编译器会对其进行完整的编译。
条件编译的本质:
-预编译器根据条件编译指令有选择的删除代码
-编译器不知道代码分支的存在
-if...else...语句在运行期进行分支判断
-条件编译指令在预编译期进行分支判断
-可以通过命令行定义宏
gcc环境下: gcc -Dmacro=value file.c 或 gcc -Dmacro file.c
vc环境下:cl -Dmacro=value file.c 或 cl -Dmacro file.c
对于上边的代码,我们屏蔽掉宏定义语句:#define FLAG 1,然后通过命令行定义宏,结果是一样的,大家可以自行实验。
通过以上的讲解,相信大家对条件编译有了一个比较清晰的认识了,同理,条件编译指令还有#ifdef、#ifndef等。下边我们来看看#include,带#的我们都可以理解为预处理器指令,都会在预处理阶段进行处理。
-#include的本质是将已经存在的文件内容嵌入至当前文件中
-#include的间接包含同样会产生嵌入文件内容的操作
为防止间接包含同一个头文件产生的重复定义的编译错误,我们在写头文件时,通常需要加上条件编译,如下:
#ifndef __FILENAME_H__ //名称一般与头文件名一致且为大写,例如此处的头文件名就为:filename.h
#define __FILENAME_H__
//头文件内容
#endif
在头文件中加上预编译指令,这样就能防止间接包含同一个头文件产生的重定义的编译错误。
条件编译的意义:
-条件编译使得我们可以按不同的条件编译不同的代码段,因而可以产生不同的目标代码
-#if...#else...#endif被预编译器处理,而if...else...被编译器处理,必然被编译进目标代码
-实际工程中条件编译主要用于以下两种情况
a、不同的产品线公用一份代码
b、区分编译产品的调试版和发布版
请看下边的代码,实际工程中是怎么通过条件 编译来实现不同产品、调试版、发布版的区分
//product.h头文件
#define DEBUG 1
#define HIGH 1
//main.c文件
#include <stdio.h>
#include "product.h"
#if DEBUG
#define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s)
#else
#define LOG(s) NULL
#endif
#if HIGH
void f()
{
printf("This is the high level product!\n");
}
#else
void f()
{
}
#endif
int main()
{
LOG("Enter main() ...");
f();
printf("1. Query Information.\n");
printf("2. Record Information.\n");
printf("3. Delete Information.\n");
#if HIGH
printf("4. High Level Query.\n");
printf("5. Mannul Service.\n");
printf("6. Exit.\n");
#else
printf("4. Exit.\n");
#endif
LOG("Exit main() ...");
return 0;
}
我们来对两个文件进行编译运行,看看结果是什么:
这样,我们就可以通过修改product.h头文件中的宏,就能产生不同版本的可执行文件了。
总结:
-通过编译器命令行能够定义预处理器使用的宏
-条件编译可以避免重复包含同一个头文件
-条件编译是在工程开发中可以区别不同产品线的代码
-条件编译可以定义产品的发布版和调试版