美文网首页
精解C语言预处理命令(四)之#if、##ifdef、#ifnde

精解C语言预处理命令(四)之#if、##ifdef、#ifnde

作者: KangSmit的算法那些事儿 | 来源:发表于2020-04-20 15:01 被阅读0次

    假如现在要开发一个C语言程序,让它输出红色的文字,并且要求跨平台,在 Windows 和 Linux 下都能运行,怎么办呢?

    这个程序的难点在于,不同平台下控制文字颜色的代码不一样,我们必须要能够识别出不同的平台。

    Windows 有专有的宏_WIN32,Linux 有专有的宏__linux__,以现有的知识,我们很容易就想到了 if else,请看下面的代码:

    1.  #include <stdio.h>
    2.  int main(){
    3.  if(_WIN32){
    4.  system("color 0c");
    5.  printf("http://c.biancheng.net\n");
    6.  }else if(__linux__){
    7.  printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m");
    8.  }else{
    9.  printf("http://c.biancheng.net\n");
    10.  }
    
    12.  return 0;
    13.  }
    
    #include <stdio.h>
    int main(){
        if(_WIN32){
            system("color 0c");
            printf("http://c.biancheng.net\n");
        }else if(__linux__){
            printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m");
        }else{
            printf("http://c.biancheng.net\n");
        }
    
        return 0;
    }
    

    但这段代码是错误的,在 Windows 下提示 linux 是未定义的标识符,在 Linux 下提示 _Win32 是未定义的标识符。对上面的代码进行改进:

    1.  #include <stdio.h>
    2.  int main(){
    3.  #if _WIN32
    4.  system("color 0c");
    5.  printf("http://c.biancheng.net\n");
    6.  #elif __linux__
    7.  printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m");
    8.  #else
    9.  printf("http://c.biancheng.net\n");
    10.  #endif
    
    12.  return 0;
    13.  }
    
    
    #include <stdio.h>
    int main(){
        #if _WIN32
            system("color 0c");
            printf("http://c.biancheng.net\n");
        #elif __linux__
            printf("\033[22;31mhttp://c.biancheng.net\n\033[22;30m");
        #else
            printf("http://c.biancheng.net\n");
        #endif
    
        return 0;
    }
    

    if、#elif、#else 和 #endif 都是预处理命令

    以上整段代码的意思是:如果宏 _WIN32 的值为真,就保留第 4、5 行代码,删除第 7、9 行代码;如果宏 linux 的值为真,就保留第 7 行代码;如果所有的宏都为假,就保留第 9 行代码。

    这些操作都是在预处理阶段完成的,多余的代码以及所有的宏都不会参与编译,不仅保证了代码的正确性,还减小了编译后文件的体积。

    这种能够根据不同情况编译不同代码、产生不同目标文件的机制,称为条件编译。条件编译是预处理程序的功能,不是编译器的功能。

    条件编译需要多个预处理命令的支持,下面一一讲解。

    ## #if 的用法
    
    #if 用法的一般格式为:
    
    #if 整型常量表达式1
        程序段1
    #elif 整型常量表达式2
        程序段2
    #elif 整型常量表达式3
        程序段3
    #else
        程序段4
    #endif
    

    它的意思是:如常“表达式1”的值为真(非0),就对“程序段1”进行编译,否则就计算“表达式2”,结果为真的话就对“程序段2”进行编译,为假的话就继续往下匹配,直到遇到值为真的表达式,或者遇到 #else。这一点和 if else 非常类似。

    需要注意的是,#if 命令要求判断条件为“整型常量表达式”,也就是说,表达式中不能包含变量,而且结果必须是整数;而 if 后面的表达式没有限制,只要符合语法就行。这是 #if 和 if 的一个重要区别。

    elif 和 #else 也可以省略,如下所示:

    1.  #include <stdio.h>
    2.  int main(){
    3.  #if _WIN32
    4.  printf("This is Windows!\n");
    5.  #else
    6.  printf("Unknown platform!\n");
    7.  #endif
    
    9.  #if __linux__
    10.  printf("This is Linux!\n");
    11.  #endif
    
    13.  return 0;
    14.  }
    
    
    #include <stdio.h>
    int main(){
        #if _WIN32
            printf("This is Windows!\n");
        #else
            printf("Unknown platform!\n");
        #endif
    
        #if __linux__
            printf("This is Linux!\n");
        #endif
    
        return 0;
    }
    
    ## #ifdef 的用法
    
    #ifdef 用法的一般格式为:
    
    #ifdef  宏名
        程序段1
    #else
        程序段2
    #endif
    

    它的意思是,如果当前的宏已被定义过,则对“程序段1”进行编译,否则对“程序段2”进行编译。

    也可以省略 #else:

    #ifdef  宏名
        程序段
    #endif
    

    VS/VC 有两种编译模式,Debug 和 Release。在学习过程中,我们通常使用 Debug 模式,这样便于程序的调试;而最终发布的程序,要使用 Release 模式,这样编译器会进行很多优化,提高程序运行效率,删除冗余信息。

    为了能够清楚地看到当前程序的编译模式,我们不妨在程序中增加提示,请看下面的代码:

    
    1.  #include <stdio.h>
    2.  #include <stdlib.h>
    3.  int main(){
    4.  #ifdef _DEBUG
    5.  printf("正在使用 Debug 模式编译程序...\n");
    6.  #else
    7.  printf("正在使用 Release 模式编译程序...\n");
    8.  #endif
    
    10.  system("pause");
    11.  return 0;
    12.  }
    
    #include <stdio.h>
    #include <stdlib.h>
    int main(){
        #ifdef _DEBUG
            printf("正在使用 Debug 模式编译程序...\n");
        #else
            printf("正在使用 Release 模式编译程序...\n");
        #endif
    
        system("pause");
        return 0;
    }
    

    当以 Debug 模式编译程序时,宏 _DEBUG 会被定义,预处器会保留第 5 行代码,删除第 7 行代码。反之会删除第 5 行,保留第 7 行。

    #ifndef 的用法

    #ifndef 用法的一般格式为:
    
    #ifndef 宏名
        程序段1 
    #else 
        程序段2 
    #endif
    

    与 #ifdef 相比,仅仅是将 #ifdef 改为了 #ifndef。它的意思是,如果当前的宏未被定义,则对“程序段1”进行编译,否则对“程序段2”进行编译,这与 #ifdef 的功能正好相反。

    三者之间的区别

    最后需要注意的是,#if 后面跟的是“整型常量表达式”,而 #ifdef 和 #ifndef 后面跟的只能是一个宏名,不能是其他的。

    例如,下面的形式只能用于 #if:

    
    1.  #include <stdio.h>
    2.  #define NUM 10
    3.  int main(){
    4.  #if NUM == 10 || NUM == 20
    5.  printf("NUM: %d\n", NUM);
    6.  #else
    7.  printf("NUM Error\n");
    8.  #endif
    9.  return 0;
    10.  }
    
    #include <stdio.h>
    #define NUM 10
    int main(){
        #if NUM == 10 || NUM == 20
            printf("NUM: %d\n", NUM);
        #else
            printf("NUM Error\n");
        #endif
        return 0;
    }
    

    运行结果:

    NUM: 10
    

    再如,两个宏都存在时编译代码A,否则编译代码B:

    1.  #include <stdio.h>
    2.  #define NUM1 10
    3.  #define NUM2 20
    4.  int main(){
    5.  #if (defined  NUM1 && defined  NUM2)
    6.  //代码A
    7.  printf("NUM1: %d, NUM2: %d\n", NUM1, NUM2);
    8.  #else
    9.  //代码B
    10.  printf("Error\n");
    11.  #endif
    12.  return 0;
    13.  }
    
    #include <stdio.h>
    #define NUM1 10
    #define NUM2 20
    int main(){
        #if (defined NUM1 && defined NUM2)
            //代码A
            printf("NUM1: %d, NUM2: %d\n", NUM1, NUM2);
        #else
            //代码B
            printf("Error\n");
        #endif
        return 0;
    }
    

    运行结果:

    NUM1: 10, NUM2: 20
    

    ifdef 可以认为是 #if defined 的缩写。

    相关文章

      网友评论

          本文标题:精解C语言预处理命令(四)之#if、##ifdef、#ifnde

          本文链接:https://www.haomeiwen.com/subject/cmkdihtx.html