--事物的难度远远低于对事物的恐惧!
最近出差较多,没什么时间记录博客笔记,刚好乘五一假期好好写一点。今天我们来看看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头文件中的宏,就能产生不同版本的可执行文件了。
总结:
-通过编译器命令行能够定义预处理器使用的宏
-条件编译可以避免重复包含同一个头文件
-条件编译是在工程开发中可以区别不同产品线的代码
-条件编译可以定义产品的发布版和调试版