条件编译

  • 条件编译
    • 条件编译的格式
      • 常见形式
      • defined运算符
      • #if的使用
      • #if defined的使用
      • #if和#elif命令
      • #ifdef和#ifndef命令
      • #if #endif的用法
      • #ifdef #endif的用法
  • 总结

条件编译

一般情况下,源程序中的所有行都参与编译。但有时希望对其中一部分内容只在满足一定条件下才进行编译,即对一部分内容指定编译条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。

条件编译命令指定预处理器依据特定的条件来判断保留或删除某段源代码。
例如,可以使用条件编译让源代码适用于不同的目标系统,而不需要管理该源代码的各种不同版本。

条件编译的格式

条件编译区域以#if#ifdef#ifndef等命令作为开头,以#endif命令结尾。条件编译区域可以有任意数量的#elif命令,但最多一个#else命令。
以#if开头的条件编译区域具有以下格式:

#if 表达式1
[程序段1]
[#elif 表达式2
程序段2]
......
[#elif 表达式n
程序段n]
[#else
程序段n+1]
#endif
  • 语义和正常代码相同,如果表达式1成立,则编译程序段1,如果表达式2成立,则编译程序段2,否则编译程序段n+1
  • 预编译指令中的表达式与C语言本身的表达式基本一致,如逻辑运算、算术运算、位运算等均可以在预编译指令中使用
  • C语言的代码时先编译再执行,预编译指令时在编译之前进行处理,通过预编译进行宏替换、条件选择代码段,生成最后的待编译代码,最后进行编译
  • 不能忘记#endif

预处理器会依次计算条件表达式,直到发现结果非0(即true)的条件表达式,预处理器会保留对应程序段内的源代码。如果找不到值为true的表达式,并且该条件编译区域中包含#else命令,则保留#else命令程序段内的代码。

程序段中可以包含任意C源代码,也可以包含更多的命令,包括嵌套的条件式编译命令。在预处理阶段结束时,没有被预处理器保留以用于后续处理的程序段会被全部删除。

常见形式

#ifdef 标识符
程序段1
#else
程序段2
#endif

作用:当标识符已经被定义过(一般是用#define命令定义),则对程序段1进行编译,否则编译程序段2
其中#else部分也可以没有,即:

#ifdef
程序段1
#endif

在头文件中使用#ifdef和#ifndef是非常重要的,可以防止双重定义的错误。例如:在头文件aaa.h中定义了类aaa

class aaa{};

如果两次#include "aaa.h"就会出错(不一定是直接两次,有可能两个不同的头文件中都包含了这个头文件),因为相同的类不能定义两次,所以需要修改aaa.h
有时,在b.h中#inclde "a.h",在c.h中#inclde "b.h"#inclde "c.h",这时,如果不用ifndef/endif,就会包含两次a.h产生错误

#ifndef _aaa_
#define _aaa_
class aaa{};
#endif

可以避免问题。因为如果已经包含某头文件,_aaa_就已经有定义,那么#ifndef条件为假,就不会执行#ifndef和#endif之间的程序段,不会再次执行对类aaa的定义了。

defined运算符

一元运算符defined可以出现在#if或#elif命令的条件中。形式如下:

defined 标识符
defined (标识符)

如果指定的identifier是一个宏名称(已被#define定义,并且未被#undef命令取消定义),则defined表达式会生成值1.否则,defined表达式会生成值0

defined运算符相对于#ifdef和#ifndef命令的优点是:可以在更大型的预处理器表达式中使用它的值。例如:

#if defined( _unix_ )&& defined( _GNUC_ )
#endif

大多数编译器会提供预定义宏,用来识别目标系统和编译器。因此,在unix系统中,通常预先定义好了宏_unix_,而GCC编译器则会预先定义好了宏_GNUC_。类似地,微软Windows平台上地Visual C编译器会自动定义好_WIN32和宏_MSC_VER。

#if的使用

#if 表达式
程序段
#endif

if后面接表达式,如果表达式成立,就会把后面的程序段编译进去(注意是编译不是执行)

#if defined的使用

#if defined (宏)
程序段
#endif

#if后面接一个宏,如果前面定义过这个宏,编译器就会编译程序段,如果没有定义过,就不会编译。不管该宏定义的是什么以及对不对。

#if和#elif命令

作为#if和#elif命令条件的表达式,必须是整数常量预处理器表达式。与普通的整数常量表达式的区别在于:

  1. 不能再#if或#elif表达式中使用类型转换运算符
  2. 可以使用预处理运算符defined
  3. 再预处理器展开所有宏,并计算完所有的defined表达式后,会使用字符o替换掉表达式中所有其他标识符或关键字
  4. 表达式中所有带符号值都具有intmax_t类型,并且所有无符号值都具有uintmax_t类型。字符常量也会受该规则的影响。intmax_t和unitmax_t定义在头文件stdint.h中。
  5. 预处理器会把字符常量和字符串变量中的字符与转义序列转换成字符集中对应的字符。然而,字符常量再预处理器表达式和在后期编译阶段是否具有相同的值,取决于实现版本。

#ifdef和#ifndef命令

通过#ifdef和#ifndef命令测试某个宏是否已被定义。

#ifdef 标识符
#ifndef 标识符

等同于:

#if defined (标识符)
#if !defined (标识符)

如果identifier不是宏名称,则#ifndef标识符后面的条件代码被保留。

#if #endif的用法

#ifdef #endif的用法

#ifdef和#endif必须成对使用。理论上可以出现在任何地方(头文件和实现文件中),通常为了放置头文件被多次包含,在头文件中使用是必须的:

#ifndef MY_HEAD_H    //头文件开头,注意不要和其它头文件冲突
头文件声明
#endif

总结

把头文件的内容都放在#ifndef和#endif中。无论头文件会不会被多个文件引用,都加上条件编译。一般格式为:

#ifndef <标识>
#define <标识>
程序段
#endif

标识理论上可以自由命名,但是每个头文件的这个标识都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的.也写成下划线。如:stdio.h

#ifndef _STDIO_H_
#define _STDIO_H_
程序段
#endif

【C语言】#ifdef和#endif条件编译相关推荐

  1. 条件编译#ifdef 和#endif

    转于http://blog.csdn.net/fly_yr/article/details/39964035 C++中 #ifdef 和#endif的作用 一般情况下,源程序中所有的行都参加编译.但是 ...

  2. vc++学习篇(三)——预处理命令之条件编译(#ifdef,#else,#endif,#if等)

    预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作.说白了,就是对源文件进行编译前,先对预处理部分进行处理,然后对处理后的代码进行编译.这样做的好处是,经过处理后的代码,将会变的很精短.   ...

  3. uni-app条件编译:#ifdef #ifndef #endif

    uni-app条件编译:#ifdef #ifndef #endif 语法: // #ifdef %PLATFORM% 这些代码只在该平台编译 // #endif #ifdef : if defined ...

  4. #ifdef,#else,#endif,#if用法详解(转)

    #ifdef,#else,#endif,#if用法详解(转) 2011-04-22 10:11 预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作.说白了,就是对源文件进行编译前,先对预处理 ...

  5. c语言if多条件并列_C/C++编程笔记:C语言预编译指令—条件编译,零基础推荐收藏

    一. 内容概述 本文主要介绍c语言中条件编译相关的预编译指令,包括#define.#undef.#ifdef.#ifndef.#if.#elif.#else.#endif.defined. 二.条件编 ...

  6. C++中 #ifdef 和#endif的用法与作用详解

    一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是"条件编译".有时,希望当满足某条件时对一组 ...

  7. #ifdef #else #endif #fi #ifndef 的用法

    预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作.说白了,就是对源文件进行编译前,先对预处理部分进行处理,然后对处理后的代码进行编译.这样做的好处是,经过处理后的代码,将会变的很精短.   ...

  8. #ifdef #else #endif 的用法

    预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作.说白了,就是对源文件进行编译前,先对预处理部分进行处理,然后对处理后的代码进行编译.这样做的好处是,经过处理后的代码,将会变的很精短. 关 ...

  9. #ifdef与#endif的作用及用法

    一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是"条件编译".有时,希望当满足某条件时对一组 ...

最新文章

  1. 【Flutter】Flutter 启动白屏问题 ( 问题描述 | 在 launch_background.xml 中设置启动过渡 UI )
  2. flink 自定义 窗口_《从0到1学习Flink》—— Flink Data transformation(转换)
  3. 据说这篇总结覆盖了一般Python开发面试中可能会问到的大部分问题
  4. WebSocket实战之————GatewayWorker使用笔记例子
  5. 旅行商问题 c++_动态多目标旅行商问题(一)
  6. 虚拟机安装---vm12+ubuntukylin16.04
  7. vs 2015查看动态库
  8. 大数据Hadoop生态圈-组件介绍
  9. J2ME 访问JAR和JAD文件中的属性
  10. Discriminative deep metric learning for face verification in the wild 度量学习(CVPR2014)
  11. R语言笔记:机器学习【K近邻】
  12. 阅读笔记-2022-Enhancing Sequential Recommendation with Graph Contrastive Learning
  13. Android Studio编译报Default interface methods are only supported starting with Android N (--min-api 24)
  14. 【日语】五十音图-一个好用的日语五十音图记忆方法
  15. 怎么做新闻软文推广?故事性新闻稿写作技巧_云媒易
  16. [引擎搭建记录] 遮罩加速的软光栅遮挡剔除
  17. C++ 静态成员变量与静态成员函数
  18. 无约束多维极值求解思路
  19. 解读 CVSS 通用评分系统中最具争议的 Scope
  20. 自学编程之路(自我记录)

热门文章

  1. vue 项目实现水印效果
  2. three js 报错, 贴图黑乎乎
  3. Excel表格怎么转PDF?这两种途径都可以
  4. 苹果历届发布会的邀请函
  5. 78 岁华科教授逐梦 40 载,国产数据库达梦冲刺 IPO
  6. node 对接微信支付的踩坑记录(服务端)
  7. 46个不得不知的生活小常识
  8. 云计算机专用显示器,电视秒变电脑显示器客厅云电脑操作方法
  9. Uncaught RangeError Maximum call stack size exceeded
  10. pycharm2018安装教程 pycharm2018永久激活教程