一、 内容概述

本文主要介绍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语言中条件编译相关的预编译指令的更多相关文章

  1. iOS中的预编译指令的初步探究

    目录 文件包含 #include #include_next #import 宏定义 #define #undef 条件编译 #if #else #endif #if define #ifdef #i ...

  2. C/C++中的预编译指令

    工作中遇到的: 一个头文件中的: #pragma warning(disable:4996)#pragma warning(disable:4244)#pragma warning(disable:4 ...

  3. c/c++中的预编译指令总结

    预处理指令提供按条件跳过源文件中的节.报告错误和警告条件,以及描绘源代码的不同区域的能力.使用术语“预处理指令”只是为了与 C 和 C++ 编程语言保持一致.在 C# 中没有单独的预处理步骤:预处理指 ...

  4. C语言的预编译,程序员必须懂的知识!【预编译指令】【预编译过程】

    由“源代码”到“可执行文件”的过程包括四个步骤:预编译.编译.汇编.链接.所以,首先就应该清楚的首要问题就是:预编译只是对程序的文本起作用,换句话说就是,预编译阶段仅仅对源代码的单词进行变换,而不是对 ...

  5. c语言中数组相关问题

    c语言中数组相关问题: 1.数组基本定义: 相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标.组成数组 ...

  6. C#中的预编译指令介绍

    原文:C#中的预编译指令介绍 1.#define和#undef 用法: #define DEBUG #undef DEBUG #define告诉编译器,我定义了一个DEBUG的一个符号,他类似一个变量 ...

  7. Unity 中使用预编译指令区分平台

    在实际项目开发过程中,我们经常会根据平台来写一些逻辑 #if UNITY_EDITOR #elif UNITY_IPHONE #elif UNITY_ANDROID #endif 使用预编译指令能很好 ...

  8. C#编写中使用预编译指令代替不停的注释

    是不是经常调试某个模块的时候,要打开一堆Console或者Debug.Log,printf 不调试的时候,又关掉.如此繁复的倒腾实在是烦 可以使用预编译指令代替这种做法 #define 自定义字段 . ...

  9. C#预编译指令

    近日工作涉及到于外部系统交互,对方提供接口:但是在双方系统未联调时,引用外部DLL,相关类实例化,提示异常错误(错误消息正常):后面操作无法进行,那如何写调试代码,即在调试时不运行某段代码,而在正式发 ...

随机推荐

  1. jsp页面如何读取从后台传来的json

    ===================================问====================================== var obj = jQuery.parseJSO ...

  2. nginx init 官方启动脚本

    #!/bin/sh # # nginx - this script starts and stops the nginx daemon # # chkconfig: - 85 15 # descrip ...

  3. HDU 1023 Train Problem II (大数卡特兰数)

    Train Problem II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  4. 【SqlServer】如何把本地SqlServer数据库部署到远程服务器上

    这里笔者使用的使用SqlServer2012,本机和远程环境均为Win7. 1.选中需要部署的数据库,右击>任务>分离.选中删除连接. 2.现在在左侧的表中就看不见刚才那个数据了. 3.在 ...

  5. Linux安装ElasticSearch-2.2.0-分词器插件(IK)

    1.在gitpub上搜索elasticsearch-analysis,能够看到所有elasticsearch的分词器: 2.安装IK分词器:https://github.com/medcl/elast ...

  6. jquery ajax 回调函数的值alert出来[object Object] 解决方法

    $("#activity_project").change(function(){ var pro=$("#activity_project").val(); ...

  7. Spring Cloud问题分析

    基于Spring Cloud框架开发时,经常会碰到各种开发问题,那么碰到这些问题时如何去解决呢?下面描述基于Spring Cloud问题定位的基本思路,大概可以分为如下几步: 排查配置问题 环境问题 ...

  8. 【转载并整理】ORACLE锁机制

    转载文章:http://blog.csdn.net/liuyiy/article/details/25005393 转载文章:http://www.cnblogs.com/jiyuqi/p/37017 ...

  9. Map和JSON的互相转换

    JSON-Lib方式 /**   * 函数注释:parseJSON2Map()<br>   * 用途:该方法用于json数据转换为<Map<String, Object> ...

  10. Python 爬虫实例(15) 爬取 百度百聘(微信公众号)

    今天闲的无聊,爬取了一个网站,百度百聘,仅供学习参考 直接上代码: #-*-coding:utf-8-*- from common.contest import * def spider(): hea ...