C进阶养成记 - 养成记22:条件编译使用分析

--事物的难度远远低于对事物的恐惧!

    最近出差较多,没什么时间记录博客笔记,刚好乘五一假期好好写一点。今天我们来看看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头文件中的宏,就能产生不同版本的可执行文件了。


总结:

    -通过编译器命令行能够定义预处理器使用的宏

    -条件编译可以避免重复包含同一个头文件

    -条件编译是在工程开发中可以区别不同产品线的代码

    -条件编译可以定义产品的发布版和调试版



猜你喜欢

转载自blog.csdn.net/lms1008611/article/details/80140974