假如现在要开发一个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. }
  11. return 0;
  12. }

但这段代码是错误的,在 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
  11. return 0;
  12. }

#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
  8. #if __linux__
  9. printf("This is Linux!\n");
  10. #endif
  11. return 0;
  12. }

#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
  9. system("pause");
  10. return 0;
  11. }

当以 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. }

运行结果:
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. }

运行结果:
NUM1: 10, NUM2: 20

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

C语言:条件编译的更多相关文章

  1. (五)c语言条件编译#ifdef与#if defined

    c语言条件编译#ifdef与#if defined defined NAME是用来判断NAME是否被定义了(被用define定义了). #ifdef NAME == #if defined(NAME) ...

  2. c语言条件编译#ifdef与#if defined

    c语言条件编译#ifdef与#if defined   c语言条件编译#ifdef与#if defined 摘自:https://www.cnblogs.com/zhangshenghui/p/566 ...

  3. c语言条件编译和预编译

    转自http://www.cnblogs.com/rusty/archive/2011/03/27/1996806.html 一.C语言由源代码生成的各阶段如下: C源程序->编译预处理-> ...

  4. C语言条件编译

    使用与平台有关的C语言函数,可能会使得程序不具有可移植性.比如Socket编程.多线程编程等是与平台有关的. 若想将程序做成平台无关的就需要用到与平台相关的条件编译. 下面转自:http://blog ...

  5. C语言条件编译及编译预处理阶段(转)

    一.C语言由源代码生成的各阶段如下: C源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件 其中 编译预处理阶段,读取c源程序,对其中的 ...

  6. 【转】C语言条件编译及编译预处理阶段

    原文: http://www.cnblogs.com/rusty/archive/2011/03/27/1996806.html 1. 宏定义(宏代换,宏替换,宏: 宏定义是C语言提供的3中预处理功能 ...

  7. C语言条件编译(#if,#ifdef,#ifndef,#endif,#else,#elif)

    1.条件编译介绍 条件编译(conditional compiling)命令指定预处理器依据特定的条件来判断保留或删除某段源代码.例如,可以使用条件编译让源代码适用于不同的目标系统,而不需要管理该源代 ...

  8. 条件编译,C语言条件编译详解

    条件编译是指预处理器根据条件编译指令,有条件地选择源程序代码中的一部分代码作为输出,送给编译器进行编译.主要是为了有选择性地执行相应操作,防止宏替换内容(如文件等)的重复包含.常见的条件编译指令如表 ...

  9. C语言-条件编译使用分析

    1.基本概念 条件编译的行为类似于C语言中的if…else… 条件编译是预编译指示命令,用于控制是否编译某段代码 2.实例分析 条件编译初探     22-1.c #include <stdio ...

  10. C语言 条件编译(if )

    #include <stdio.h> #define NUM -1 int main(int argc, const char * argv[]) { #if NUM > 0 pri ...

随机推荐

  1. 3D结构光

    3D结构光 3D结构光的整个系统包含结构光投影设备.摄像机.图像采集和处理系统.其过程就是投影设备发射光线到被测物体上,摄像机拍摄在被测物体上形成的三维光图形,拍摄图像经采集处理系统处理后获得被测物体 ...

  2. PyTorch 图像分类

    PyTorch 图像分类 如何定义神经网络,计算损失值和网络里权重的更新. 应该怎么处理数据? 通常来说,处理图像,文本,语音或者视频数据时,可以使用标准 python 包将数据加载成 numpy 数 ...

  3. P1091 [NOIP2004 提高组] 合唱队形

    题目描述 $N$位同学站成一排,音乐老师要请其中的$\left ( N-K\right )$位同学出列,使得剩下的$K$位同学排成合唱队形. 合唱队形是指这样的一种队形:设$K$位同学从左到右依次编号 ...

  4. 【NX二次开发】Block UI 从列表选择部件

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  5. 【VBA】列号与字母(列名)的相互转换 (自定义函数)

    1. '列号转字母(列名) Function Num2Name(ByVal ColumnNum As Long) As String On Error Resume Next Num2Name = & ...

  6. 【数论】8.30题解-prime素数密度 洛谷p1835

    prime 洛谷p1835 题目描述 给定区间[L, R](L <= R <= 2147483647, R-L <= 1000000),请计算区间中 素数的个数. 输入输出 输入 两 ...

  7. redis学习第二天

    Redis 在 2.8.9 版本之后添加了 HyperLogLog 结构 Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常 ...

  8. css初级代码

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8& ...

  9. Ansible自动化运维应用实战

    实验环境 centos7.4 主机名称 IP 配置 用途 controlnode 172.16.1.120 1核/1G/60G ansible slavenode1 172.16.1.121 1核/1 ...

  10. 1、mysql基础入门(2)

    1.4.常用非关系型数据库产品介绍: 1.Memcached(key-value)数据库: