c语言中条件编译相关的预编译指令
一、 内容概述
本文主要介绍c语言中条件编译相关的预编译指令,包括#define、#undef、#ifdef、#ifndef、#if、#elif、#else、#endif、defined。
二、条件编译
条件编译是根据实际定义宏(某类条件)进行代码静态编译的手段。可根据表达式的值或某个特定宏是否被定义来确定编译条件。
最常见的条件编译是防止重复包含头文件的宏,形式跟下面代码类似:
#ifndef ABCD_H
#define ABCD_H // ... some declaration codes #endif // #ifndef ABCD_H
在实现文件中通常有如下类似的定义:
#ifdef _DEBUG // ... do some operations #endif #ifdef _WIN32 // ... use Win32 API #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指令的配合等。
参考资料:
Preprocessor Directives http://msdn.microsoft.com/zh-cn/library/aa381033
c语言中条件编译相关的预编译指令的更多相关文章
- iOS中的预编译指令的初步探究
目录 文件包含 #include #include_next #import 宏定义 #define #undef 条件编译 #if #else #endif #if define #ifdef #i ...
- C/C++中的预编译指令
工作中遇到的: 一个头文件中的: #pragma warning(disable:4996)#pragma warning(disable:4244)#pragma warning(disable:4 ...
- c/c++中的预编译指令总结
预处理指令提供按条件跳过源文件中的节.报告错误和警告条件,以及描绘源代码的不同区域的能力.使用术语“预处理指令”只是为了与 C 和 C++ 编程语言保持一致.在 C# 中没有单独的预处理步骤:预处理指 ...
- C语言的预编译,程序员必须懂的知识!【预编译指令】【预编译过程】
由“源代码”到“可执行文件”的过程包括四个步骤:预编译.编译.汇编.链接.所以,首先就应该清楚的首要问题就是:预编译只是对程序的文本起作用,换句话说就是,预编译阶段仅仅对源代码的单词进行变换,而不是对 ...
- c语言中数组相关问题
c语言中数组相关问题: 1.数组基本定义: 相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标.组成数组 ...
- C#中的预编译指令介绍
原文:C#中的预编译指令介绍 1.#define和#undef 用法: #define DEBUG #undef DEBUG #define告诉编译器,我定义了一个DEBUG的一个符号,他类似一个变量 ...
- Unity 中使用预编译指令区分平台
在实际项目开发过程中,我们经常会根据平台来写一些逻辑 #if UNITY_EDITOR #elif UNITY_IPHONE #elif UNITY_ANDROID #endif 使用预编译指令能很好 ...
- C#编写中使用预编译指令代替不停的注释
是不是经常调试某个模块的时候,要打开一堆Console或者Debug.Log,printf 不调试的时候,又关掉.如此繁复的倒腾实在是烦 可以使用预编译指令代替这种做法 #define 自定义字段 . ...
- C#预编译指令
近日工作涉及到于外部系统交互,对方提供接口:但是在双方系统未联调时,引用外部DLL,相关类实例化,提示异常错误(错误消息正常):后面操作无法进行,那如何写调试代码,即在调试时不运行某段代码,而在正式发 ...
随机推荐
- __cplusplus的用法(转)
经常在/usr/include目录下看到这种字句: #ifdef __cplusplusextern "C" {#endif...#ifdef __cplusplus}#endif ...
- Nginx Rewrite正则表达式案例
前两天简单整理了下Nginx的URL Rewrite基本指令,今天谈谈Nginx Rewrite的location正则表达式. 1.Nginx Rewrite 基本标记(flags) last 相当于 ...
- 搞不懂为什么开发人员爱iOS恨Android?
导读:很多网站发表文章大同小异.唯有这个不同点,给大家分享. Android和iOS的较量一直都是人们津津乐道的话题.两个平台各有各的优势所在,同时也都力图能在各个方面赶超对手.对于用户来说,青菜萝卜 ...
- cmake3.8X64编译opencv3.2出现opencv_ffmpeg、opencv_ffmpeg_64、ippicv_windows_20151201.zip无法下载问题解决方案
cmake版本:cmake3.8.0 开发环境:Visual Studio 2017 x64 解决方法:1.在opencv安装目录下sources\3rdparty\ffmpeg\ffmpeg.cma ...
- ==和equals的简单比较
前言:==和equals这个两个东西,经常放在一块做比较,下面我也给出一个简单的例子,对他俩进行一个简单的比较,先看例子,然后在看结论.(实验环境:win7+jdk7) 1:==和equals简单比较 ...
- linux文件系统 - 初始化(三)
执行init程序 一.目的 内核加载完initrd文件后,为挂载磁盘文件系统做好了必要的准备工作,包括挂载了sysfs.proc文件系统,加载了磁盘驱动程序驱动程序等.接下来,内核跳转到用户空间的in ...
- Loader Lock引起的一个Bug
在Windows中,让程序模块化实现的一种方式,就是让事实上现为动态链接库. 然后在主程序启动的时候隐式或者显示的去载入动态链接库.可是假设不恰当的编写动态链接库的DllMain函数,将会引起意想不到 ...
- CSS3选择器之学习笔记
首先说first-child与last-child,这两个选择器很容易明白,就是父元素下的第一个子元素和最后一个子元素.而nth-child和nth-last-child则是父元素下指定序号的子元素, ...
- 【OpenCV】给图像加入噪声
图像噪声使图像在获取或是传输过程中收到随机信号干扰,妨碍人们对图像理解及分析处理的信号.非常多时候将图像噪声看做多维随机过程,因而描写叙述噪声的方法全然能够借用随机过程的描写叙述,也就是使用随机过程的 ...
- 基于TransactionScope类的分布式隐式事务
System.Transactions 命名空间中除了上一节中提到的基于 Transaction 类的显式编程模型,还提供使用 TransactionScope 类的隐式编程模型,它与显示编程模型相比 ...