C语言#if、#elif、#else和#endif条件编译的用法(非常详细)

 
在C语言中,程序员可以根据不同的条件,有选择性地编译不同的代码块(忽略其它的代码块),从而产生不同的目标文件,这种机制称为条件编译。

借助条件编译,我们可以在同一份源代码中包含针对不同操作系统、硬件架构或功能配置的代码,而无需维护多个独立的源文件。

条件编译是预处理器的功能,不是编译器的功能。条件编译通过以#开头的预处理命令来完成,包括 #if、#elif、#else、#endif、#ifdef 和 #ifndef。本文先介绍前四个命令,后两个命令请转到:C语言#ifdef和#ifndef命令的用法

条件编译的用法和示例

#if、#elif、#else 和 #endif 允许我们根据特定的条件(一个表达式的值),来决定哪些代码段应该被编译,哪些应该被忽略。它们的基本用法如下:
#if 常量表达式1
    //代码段1
    //如果 常量表达式1 的值为真,则编译 代码段1,忽略其它代码
#elif 常量表达式2
    //代码段2
    //如果 常量表达式2 的值为真,则编译 代码段2,忽略其它代码
#elif 常量表达式3
    //代码段3
    //如果 常量表达式3 的值为真,则编译 代码段3,忽略其它代码
#else
    //代码段n
    //如果以上表达式的值都为假,则编译 代码段n,忽略其它代码
#endif
整体上的执行流程为:如果常量表达式1的值为真(非 0),就对代码段1进行编译,否则就计算常量表达式2,结果为真的话就对代码段2进行编译,为假的话就继续往下匹配,直到遇到值为真的表达式,或者遇到 #else。

#if #else 命令和 if else 语句的用法非常类似,都是一种分支结构。但是,#if 命令要求判断条件为“常量表达式”,不能包含变量以及函数调用,而 if 语句后面的表达式没有限制,只要符合语法就行。这是 #if 和 if 的一个重要区别。

#if #else 是在预处理阶段进行替换,无法获取变量的值,所以表达式中不能包含变量。

#elif 和 #else 都可以省略,也就是写成下面的形式:
#if 常量表达式
    //代码段1
    // 如果 常量表达式 的值为真,则编译 代码段1
#else
    //代码段2
    //如果 常量表达式 的值为假,则编译 代码段2
#endif
或者:
#if 常量表达式
    //代码段
    //如果 常量表达式 的值为真,则编译这里的 代码段
#endif

示例1:同时使用 #if、#elif 和 #else 命令:
#include <stdio.h>

#define LEVEL 2

#if LEVEL == 1
    #define MESSAGE "Low priority"
#elif LEVEL == 2
    #define MESSAGE "Medium priority"
#elif LEVEL == 3
    #define MESSAGE "High priority"
#else
    #define MESSAGE "Unknown priority"
#endif

int main() {
    printf("Task priority: %s\n", MESSAGE);
    return 0;
}
运行结果:

Task priority: Medium priority

我们根据 LEVEL 宏的值来定义不同的 MESSAGE,如果 LEVEL 的值不是 1、2 或 3,那么会使用 #else 分支中定义的默认消息。本例中,第 5~13 行的代码,只有第 8 行代码被编译,其它代码在预处理完成以后就不存在了。

示例2:只使用 #if 命令:
#include <stdio.h>

#define DEBUG 1

int main() {
    #if DEBUG
        printf("Debug mode is enabled.\n");
    #endif

    //TODO:
    return 0;
}
在这个例子中,如果 DEBUG 宏被定义为非零值,那么 printf 语句就会被编译到最终的程序中。否则,这行代码会被忽略。

条件编译的嵌套使用

条件编译命令可以嵌套使用,这使得我们能够创建更加复杂的判断逻辑,请看下面的例子(示例3):
#define DEBUG 1
#define VERBOSE_DEBUG 1

#if DEBUG
    printf("Debug mode enabled.\n");
    #if VERBOSE_DEBUG
        printf("Verbose debug information will be displayed.\n");
    #endif
#else
    printf("Running in release mode.\n");
#endif
在这个例子中,我们有一个嵌套的条件编译结构。只有当 DEBUG 被定义为非零值时,内部的#if VERBOSE_DEBUG条件才会被检查。

关于 #if 和 #elif 后面的表达式

#if 和 #elif 后面的常量表达式中,可以包含各种算术运算符、逻辑运算符和关系运算符,以实现更复杂的条件判断。请看下面的例子(示例4):
#include <stdio.h>

#define M 20
#define N 40

int main(){
    #if M+N>100
        printf("The value is too large.\n",);
    #elif M+N<=100 && M+N>50
        printf("The value is right.\n");
    #else
        printf("The value is too small.\n");
    #endif

    return 0;
}
运行结果:

The value is right.

虽然这些表达式看起来复杂,但是在程序运行之前就能推算出它们的值;而一旦包含了变量或者函数调用,就必须等到程序运行以后才能获取它们的值,这就超出预处理器的能力了。

总结

C语言条件编译允许只编译源程序中满足条件的代码段,使生成的目标程序较短,从而减少了内存的开销,并提高了程序的效率。

最后请注意,#endif 不能省略,它必须和 #if 配对出现,用以结束条件编译。