我们在看一些开源的源代码的时候,经常会看到如下情景:

# if defined(_PTHREADS) && !defined(_NOTHREADS)
#     define __STL_PTHREADS
# endif
 
# if defined(_UITHREADS) && !defined(_PTHREADS) && !defined(_NOTHREADS)
#     define __STL_UITHREADS
# endif
 
# if defined(__sgi) && !defined(__GNUC__)
#   include <standards.h>
#   if !defined(_BOOL)
#     define __STL_NO_BOOL
#   endif
#   if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
#     define __STL_STATIC_CONST_INIT_BUG
#   endif
#   if defined(_WCHAR_T_IS_KEYWORD)
#     define __STL_HAS_WCHAR_T
#   endif
#  .......
#   if _COMPILER_VERSION >= 730 && defined(_STANDARD_C_PLUS_PLUS)
#     define __SGI_STL_USE_AUTO_PTR_CONVERSIONS
#   endif
# endif

曾经菜鸟和现在依然还是菜鸟的我,对于这个满眼的#ifdef,#ifndef,#define,#endif,心里犯怵。我擦,这是神马鸟东西啊!其实,这些是条件编译。对于不同平台,许多的参数定义都不是不同,那么条件编译就是对付跨平台的炸弹,炸毁平台之间的藩篱。

先说说#ifndef,#define,#endif,我们对此十分的熟悉。在我们项目的许多头文件里面,我们经常是这样:

#ifndef JSON_AUTOLINK_H_INCLUDED
#define JSON_AUTOLINK_H_INCLUDED
 
.......
 
#endif // JSON_AUTOLINK_H_INCLUDED

话说这样是为了解决重复定义的问题。例如:我在a.h中定义了class A,在b.h中也定义了class A,那么在c.cpp中都包含了a.h和b.h,按照包含头函数的习惯,这个class A是重复定义了。为了防止这样情况的出现,就出现上面的做法。

在来说说,#ifdef和#endif。一般情况下,源程序中所有的行都参加编译。但是,有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。那么怎么使用呢?看看以下格式:

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

那么,我们在config文件中就可以来选择说,要编译那个程序段。这是不是很爽呢?我不用写两份,只写一份,然后编译的时候调整以下就好了。

例如下面的代码

#ifdef JSON_VALUE_USE_INTERNAL_MAP
   class ValueAllocator;
   class ValueMapAllocator;
   class ValueInternalLink;
   class ValueInternalArray;
   class ValueInternalMap;
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP

我在config文件中没有#define JSON_VALUE_USE_INTERNAL_MAP的时候,上面这段代码是被忽略的。当我在config文件中这样写:

# define JSON_USE_EXCEPTION 1
 
# define JSON_VALUE_USE_INTERNAL_MAP    // 增加了这个之后,整个项目中的JSON_VALUE_USE_INTERNAL_MAP这个部分就可以进行编译了
 
# ifdef JSON_IN_CPPTL
#  include <cpptl/config.h>
#  ifndef JSON_USE_CPPTL
#   define JSON_USE_CPPTL 1
#  endif
# endif
......

#define这个东西可以定义宏,参数之类的,也可以作为条件编译中的阀门,例如上面的例子。宏就不介绍了。我不大喜欢,因为我可以用内联函数来代替。内联函数多帅啊,不好好用可惜的说。

在次将眼光转到本文开始的地方,有许多的条件编译语句,有些需要解释。

# if defined(_PTHREADS) && !defined(_NOTHREADS)    // 假如有定义_PTHREADS和没有定义_NOTHREADS,那么就定义__STL_PTHREADS吧。听起来有点囧!
#     define __STL_PTHREADS
# endif

这种条件编译语句很像if(){}else{},理解起来难度不大。反正好好看就问题不大了。

最后,本文有点像代码贴。文字的部分不多,用贴代码来理解。说的不好,请大牛们指正,谢谢了

参考文献:

1. 《C语言程序设计》

2. 《C和指针》

3. 《C专家编程》

转载于:https://www.cnblogs.com/ComputerG/archive/2012/03/02/2377726.html

#ifdef,#ifndef,#define,#endif解析(原)相关推荐

  1. [Windows编程] #pragma once 和#ifndef ... #define ... #endif 比较

    C++中防止头文件被多次include 的常见方式有: 1) 用#ifndef ...  #define ... #endif  宏 #ifndef __MYHEADER_H__ #define __ ...

  2. 【转载】#pragma once与#ifndef #define #endif的区别

    一.相同点         两者的共同点都是为了避免同一个文件被 include 多次,但是 #ifndef #define #endif 不只有这个作用.  在能够支持这两种方式的编译器上,二者并没 ...

  3. #pragma once 和 #ifndef ... #define ... #endif 的区别【转载】

    在编写程序的时候,我们经常要用到#pragma指令来设定编译器的状态或者是指示编译器完成一些特定的动作. 1. #pragma message 指令 message能够在编译消息输出窗口中输出相应的消 ...

  4. 头文件为什么要加#ifndef #define #endif

    一 #ifndef 在头文件中的作用 一个大的软件工程里有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件时,就会出现大量"重定义"的错误.这时在头文件中使用#ifn ...

  5. ifndef/define/endif的使用

    ifndef/define/endif:简而言之就是避免头文件被重复引用. (ifdef/define/endif是已定义的宏为真,ifndef/define/endif是未定义的宏为真) 在一个大型 ...

  6. #ifndef, #define, #endif 作用

    目录 #ifndef, #define, #endif 作用 #ifndef #ifdef #define #ifndef, #define, #endif 作用 #ifndef 它是if not d ...

  7. ifndef/define/endif——主要目的是防止头文件的重复包含和编译

    原文:http://www.jb51.net/article/100939.htm 原文:https://blog.csdn.net/abc5382334/article/details/180527 ...

  8. c:#ifndef, #define, #endif 作用

    #ifndef, #define, #endif 作用 #ifndef 它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义.文件包含.条件编译)中的 ...

  9. c/c++头文件中#ifndef/#define/#endif的用法

    想必很多人都看过"头文件中用到的 #ifndef/#define/#endif 来防止该头文件被重复引用".但是是否能理解"被重复引用"是什么意思?头文件被重复 ...

  10. C语言头文件为什么要加#ifndef #define #endif(防止头文件重复包含)

    当你用VC的菜单新增一个类,你会发现自动生成的代码总是类似下面的样子: #if !defined(AFX_XXXX__INCLUDED_)#define AFX_XXXX__INCLUDED_具体代码 ...

最新文章

  1. 精度45.9%,推理速度72.9FPS,百度飞桨推出工业级目标检测模型 PP-YOLO
  2. 机器人操作学习系列分享:模仿学习
  3. Java面向对象之继承,方法重写,super关键字,员工类系列继承题
  4. 1165: 零起点学算法72——首字母变大写
  5. 利用FastJSON 把list和map转换成Json
  6. think php5是什么,thinkphp5是什么
  7. linux中查看用户组标识符,Linux用户和组管理
  8. ssm如何支持热部署_最新Spring Boot实战文档推荐:项目搭建+配置+SSM整合
  9. 视频客观质量评价工具:MSU Video Quality Measurement Tool
  10. OpenGL Tutorial
  11. navicat premium使用教程 Navicat Premium mac的基本使用
  12. Win10+Pytorch0.4.1版本+cuda一键安装
  13. glide源码中包含了那种设计模式_Glide源码解读(一)
  14. 回声消除技术原理与解决办法
  15. 2020年11月最新互联网大厂面试经验分享【网易、阿里、腾讯、京东、百度、爱奇艺、字节、小米、美团、搜狐、58】
  16. MYSQL中redo log和binlog之间的区别
  17. php 半角 全角 转换,PHP半角/全角转换函数
  18. LCD1602与DHT11温湿度的使用
  19. linux 删除模块命令,Linux系统中的Modprobe命令:添加和删除Linux内核模块的方法
  20. 麒麟V10桌面版添加开机自启动程序

热门文章

  1. 一、操作系统——处理机(作业)调度算法:先来先服务算法FCFS、最短作业优先算法SJF(非抢占式)、 最短剩余时间优先算法SRTN(抢占式)、最高响应比优先算法HRRN
  2. jQuery实现PC端商城购物车模块基本功能(每个商品的小计和合计都会根据添加和删除的操作来动态计算)
  3. LeetCode 1663. 具有给定数值的最小字符串(贪心)
  4. LeetCode MySQL 1225. 报告系统状态的连续日期(date_sub + over)
  5. LeetCode 1062. 最长重复子串(二分查找)
  6. LeetCode 788. 旋转数字
  7. 剑指Offer - 面试题64. 求1+2+…+n(递归)
  8. LeetCode 1080. 根到叶路径上的不足节点(递归)
  9. LeetCode 386. 字典序排数(DFS循环)
  10. oracle rank 语法_oracle rank函数怎么用