c语言中条件编译相关的预编译指令
一、 内容概述
本文主要介绍c语言中条件编译相关的预编译指令,包括#define、#undef、#ifdef、#ifndef、#if、#elif、#else、#endif、defined。
二、条件编译
条件编译是根据实际定义宏(某类条件)进行代码静态编译的手段。可根据表达式的值或某个特定宏是否被定义来确定编译条件。
最常见的条件编译是防止重复包含头文件的宏,形式跟下面代码类似:
1 #ifndef ABCD_H 2 #define ABCD_H 3 4 // ... some declaration codes 5 6 #endif // #ifndef ABCD_H
在实现文件中通常有如下类似的定义:
1 #ifdef _DEBUG 2 3 // ... do some operations 4 5 #endif 6 7 #ifdef _WIN32 8 9 // ... use Win32 API 10 11 #endif
这些都是条件编译的常用情境。
三、条件编译中使用的预编译指令
#define 定义一个预处理宏
#undef 取消宏的定义
#if 编译预处理中的条件命令,相当于C语法中的if语句
#ifdef 判断某个宏是否被定义,若已定义,执行随后的语句
#ifndef 与#ifdef相反,判断某个宏是否未被定义
#elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if
#else 与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else
#endif #if, #ifdef, #ifndef这些条件命令的结束标志.
defined 与#if, #elif配合使用,判断某个宏是否被定义
四、预编译指令应用举例
1. #define、#undef
#define命令定义一个宏:
#define MACRO_NAME[(args)] [tokens[(opt)]]
之后出现的MACRO_NAME将被替代为所定义的标记(tokens)。宏可带参数,而后面的标记也是可选的。
宏定义,按照是否带参数通常分为对象宏、函数宏两种。
对象宏: 不带参数的宏被称为"对象宏(objectlike macro)"。对象宏多用于定义常量、通用标识。例如:
// 常量定义 #define MAX_LENGTH 100 // 通用标识,日志输出宏 #define SLog printf // 预编译宏 #define _DEBUG
函数宏:带参数的宏。利用宏可以提高代码的运行效率: 子程序的调用需要压栈出栈, 这一过程如果过于频繁会耗费掉大量的CPU运算资源。 所以一些代码量小但运行频繁的代码如果采用带参数宏来实现会提高代码的运行效率。但多数c++程序不推荐使用函数宏,调试上有一定难度,可考虑使用c++的inline代替之。例如:
// 最小值函数 #define MIN(a,b) ((a)>(b)? (a):(b)) // 安全释放内存函数 #define SAFE_DELETE(p) {if(NULL!=p){delete p; p = NULL;}}
#undef可以取消宏定义,与#define对应。
2. defined
defined用来测试某个宏是否被定义。defined(name): 若宏被定义,则返回1,否则返回0。
它与#if、#elif、#else结合使用来判断宏是否被定义,乍一看好像它显得多余, 因为已经有了#ifdef和#ifndef。defined可用于在一条判断语句中声明多个判别条件;#ifdef和#ifndef则仅支持判断一个宏是否定义。
#if defined(VAX) && defined(UNIX) && !defined(DEBUG)
和#if、#elif、#else不同,#ifdef、#ifndef、defined测试的宏可以是对象宏,也可以是函数宏。
3. #ifdef、#ifndef、#else、#endif
条件编译中相对常用的预编译指令。模式如下:
#ifdef ABC // ... codes while definded ABC #elif (CODE_VERSION > 2) // ... codes while CODE_VERSION > 2 #else // ... remained cases #endif // #ifdef ABC
#ifdef用于判断某个宏是否定义,和#ifndef功能正好相反,二者仅支持判断单个宏是否已经定义,上面例子中二者可以互换。如果不需要多条件预编译的话,上面例子中的#elif和#else均可以不写。
4. #if、#elif、#else、#endif
#if可支持同时判断多个宏的存在,与常量表达式配合使用。常用格式如下:
#if 常量表达式1 // ... some codes #elif 常量表达式2 // ... other codes #elif 常量表达式3 // ... ... #else // ... statement #endif
常量表达式可以是包含宏、算术运算、逻辑运算等等的合法C常量表达式,如果常量表达式为一个未定义的宏, 那么它的值被视为0。
#if MACRO_NON_DEFINED // 等价于 #if 0
在判断某个宏是否被定义时,应当避免使用#if,因为该宏的值可能就是被定义为0。而应当使用#ifdef或#ifndef。
注意: #if、#elif之后的宏只能是对象宏。如果宏未定义,或者该宏是函数宏,则编译器可能会有对应宏未定义的警告。
五、总结
本文主要介绍c语言中有关预编译的指令。撰写本文的目的在于理清相关概念调用,在后续预编译使用时可以找到最合适的指令及格式。比如同时满足多个宏定义的预编译、多分支预编译、#elif和#else指令的配合等。
相关文章
- dart系列之:dart语言中的特殊操作符
- Go 语言指针符号 * 和 & (pointer)
- c语言联合union的使用用途
- 第十四章 配置国家语言支持 (NLS)
- 《编译与反编译技术》—第1章1.5节高级语言及其分类
- 《R语言数据挖掘:实用项目解析》——第1章,第1.11节apply原理
- 从0开始,用Go语言搭建一个简单的后端业务系统
- 这一次,带你深入浅出Go语言切片和数组
- Scala语言中Null/Nothing/Nil/None/Unit的理解
- 系统学习JAVA第二天(JDK、JRE、JVM,JAVA语言是编译性语言也是解释性语言,JAVA语言基础)
- 《圣殿祭司的ASP.NET4.0专家技术手册》----2-1 C# 4.0语言新功能
- C 语言中的位运算符
- Squirrel语言初探(可以使用VC6或者MinGW编译)
- 为什么golang的开发效率高(编译型的强类型语言、工程角度高、在开发上的高效率主要来自于后发优势,编译快、避免趁编译时间找产品妹妹搭讪,既是强类型语言又有gc,只要通过编译,非业务毛病就很少了)
- 《R语言数据挖掘:实用项目解析》——1.6 日期与时间格式化
- 《R语言数据挖掘:实用项目解析》——小结
- python语言绘图:绘制一组beta分布图
- 【c语言】使用gumbo解析HTML
- c语言编译文件例子
- 浅析编译原理基础科普:编译是什么、高级语言低级语言是什么、如何转换、为什么需要ast、编译器转译器解释器如何处理ast
- R语言基础题及答案(四)——R语言与统计分析第四章课后习题(汤银才)
- 【历史上的今天】10 月 15 日:FORTRAN 语言正式问世;支付宝诞生第一笔交易;Tcl 语言发明者出生
- c语言输出编译时间日期行号文件名