预处理指令提供按条件跳过源文件中的节、报告错误和警告条件,以及描绘源代码的不同区域的能力。使用术语“预处理指令”只是为了与 C 和 C++ 编程语言保持一致。在 C# 中没有单独的预处理步骤;预处理指令按词法分析阶段的一部分处理。
  预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。
  文件包含:#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。
  条件编译:#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。
  布局控制:#progma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。
  宏替换:#define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。
  下面我们看一下常见的预处理指令:

  ● #define 宏定义
  ● #undef 未定义宏
  ● #include 文本包含
  ● #ifdef 如果宏被定义就进行编译
  ● #ifndef 如果宏未被定义就进行编译
  ● #endif 结束编译块的控制
  ● #if 表达式非零就对代码进行编译
  ● #else 作为其他预处理的剩余选项进行编译
  ● #elif 这是一种#else和#if的组合选项
  ● #line 改变当前的行数和文件名称
  ● #error 输出一个错误信息
  ● #pragma 为编译程序提供非常规的控制流信息
  下面我们对这些预处理进行一一的说明,考虑到宏的重要性和繁琐性,我们把它放到最后讲。
  文件包含指令:
  这种预处理使用方式是最为常见的,平时我们编写程序都会用到,最常见的用法是:
  ● #include <iostream> //标准库头文件
  ● #include <iostream.h> //旧式的标准库头文件
  ● #include "IO.h" //用户自定义的头文件
  ● #include "../file.h" //UNIX下的父目录下的头文件
  ● #include "/usr/local/file.h" //UNIX下的完整路径
  ● #include "..\file.h" //Dos下的父目录下的头文件
  ● #include "\usr\local\file.h" //Dos下的完整路径

  这里面有2个地方要注意:
  1、我们用<iostream>还是<iostream.h>?
  我们主张使用<iostream>,而不是<iostream.h>,为什么呢?我想你可能还记得我曾经给出过几点理由,这里我大致的说一下:首先,.h格式的头文件早在98年9月份就被标准委员会抛弃了,我们应该紧跟标准,以适合时代的发展。其次,iostream.h只支持窄字符集,iostream则支持窄/宽字符集。
  还有,标准对iostream作了很多的改动,接口和实现都有了变化。最后,iostream组件全部放入namespace std中,防止了名字污染。[NextPage]
  2、<io.h>和"io.h"的区别?
  其实他们唯一的区别就是搜索路径不同:
  对于#include <io.h> ,编译器从标准库路径开始搜索
  对于#include "io.h" ,编译器从用户的工作路径开始搜索
  编译控制指令:
  这些指令的主要目的是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。
  使用格式,如下:

  

  如果identifier为一个定义了的符号,your code就会被编译,否则剔除
  2、

  

  如果identifier为一个未定义的符号,your code就会被编译,否则剔除
  3、

  

  如果expression非零,your code就会被编译,否则剔除
  4、

  

  如果identifier为一个定义了的符号,your code1就会被编译,否则yourcode2就会被编译
  5、

  

  如果epression1非零,就编译your code1,否则,如果expression2非零,就编译your code2,否则,就编译your code3
  其他预编译指令
  除了上面我们说的集中常用的编译指令,还有3种不太常见的编译指令:#line、#error、#pragma,我们接下来就简单的谈一下。
  #line的语法如下:

  

  例如:#line 30 a.h 其中,文件名a.h可以省略不写。
  这条指令可以改变当前的行号和文件名,例如上面的这条预处理指令就可以改变当前的行号为30,文件名是a.h。初看起来似乎没有什么用,不过,他还是有点用的,那就是用在编译器的编写中,我们知道编译器对C++源码编译过程中会产生一些中间文件,通过这条指令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。

  

  例如:

  

  这条指令主要是给出错误信息,上面的这个例子就是,如果没有在UNIX环境下,就会输出This software requires the UNIX OS.然后诱发编译器终止。所以总的来说,这条指令的目的就是在程序崩溃之前能够给出一定的信息。
  #pragma是非统一的,他要依靠各个编译器生产者,例如,在SUN C++编译器中:

  

  预定义标识符
  为了处理一些有用的信息,预处理定义了一些预处理标识符,虽然各种编译器的预处理标识符不尽相同,但是他们都会处理下面的4种:
  1、__FILE__ 正在编译的文件的名字
  2、__LINE__ 正在编译的文件的行号
  3、__DATE__ 编译时刻的日期字符串,例如: "25 Dec 2000"
  4、__TIME__ 编译时刻的时间字符串,例如: "12:30:55"
  例如:cout<<"The file is :"<<__FILE__"<<"! The lines is:"<<__LINE__<<endl;
  预处理何去何从
  如何取代#include预处理指令,我们在这里就不再一一讨论了。
  C++并没有为#include提供替代形式,但是namespace提供了一种作用域机制,它能以某种方式支持组合,利用它可以改善#include的行为方式,但是我们还是无法取代#include。
  #progma应该算是一个可有可无的预处理指令,按照C++之父Bjarne的话说,就是:"#progma被过分的经常的用于将语言语义的变形隐藏到编译系统里,或者被用于提供带有特殊语义和笨拙语法的语言扩充。”
  对于#ifdef,我们仍然束手无策,就算是我们利用if语句和常量表达式,仍然不足以替代她,因为一个if语句的正文必须在语法上正确,满足类检查,即使他处在一个绝不会被执行的分支里面。

c/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#中的预编译指令介绍 1.#define和#undef 用法: #define DEBUG #undef DEBUG #define告诉编译器,我定义了一个DEBUG的一个符号,他类似一个变量 ...

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

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

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

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

  6. C/C++中的预编译指令(转)

    reference:https://blog.csdn.net/sunshinewave/article/details/51020421 程序的编译过程可以分为预处理.编译.汇编三部分,其中预处理是 ...

  7. C#中的预编译指令介绍[转]

    原文链接 1.#define和#undef 用法: #define DEBUG #undef DEBUG #define告诉编译器,我定义了一个DEBUG的一个符号,他类似一个变量,但是它没有具体的值 ...

  8. c语言中条件编译相关的预编译指令

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

  9. C#预编译指令

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

随机推荐

  1. spring 属性文件加载接口---PropertySourceLoader

    org.springframework.boot.config Interface PropertySourceLoader 实现类: PropertiesPropertySourceLoader, ...

  2. spring cloud 入门系列七:基于Git存储的分布式配置中心--Spring Cloud Config

    我们前面接触到的spring cloud组件都是基于Netflix的组件进行实现的,这次我们来看下spring cloud 团队自己创建的一个全新项目:Spring Cloud Config.它用来为 ...

  3. 概念这种东西--node.js

    概念是一个既简单又复杂.既招人爱又招人恨的东西.概念是对一事务或现象的抽象.抽象好了,那就太方便问题的解决了,抽象坏了,那就驴唇不对马嘴,反而会让逻辑一塌糊涂.现实中经常有这样的概念:东北人怎么怎么样 ...

  4. 4星|《亿万》:FBI大战华尔街对冲基金大鳄

    亿万:围剿华尔街大白鲨 全书尝试还原2008-2013年前后FBI指控赛克资本老板科恩通过内幕交易盈利的案件细节. 作者花了数年时间,采访了200多位当事人,阅读了海量的相关资料.书中交代了科恩的发家 ...

  5. sqli-labs学习笔记 DAY3

    DAY 3 sqli-labs lesson 6 同lesson 5,只是把单引号改为双引号 sqli-labs lesson 7 同lesson 5,只是把单引号后面加两个空格,使用Burpsuit ...

  6. 第七次ScrumMeeting博客

    第七次ScrumMeeting博客 本次会议于11月1日(三)22时整在3公寓725房间召开,持续15分钟. 与会人员:刘畅.辛德泰.窦鑫泽.张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的 ...

  7. KETTLE元数据表

    表名 说明 R_CLUSTER R_CLUSTER_SLAVE R_CONDITION R_DATABASE 数据库连接信息 R_DATABASE_ATTRIBUTE 数据库属性 R_DATABASE ...

  8. es6 babel编译

    本文主要参照阮一峰的es6入门,为提高自己写了一份随笔. 原文地址请戳这里  ECMAScript 6 入门 ECMAScript 6是JavaScript语言的下一代标准.因为当前版本的ES6是在2 ...

  9. LCA最近公共祖先(Tarjan离线算法)

    这篇博客对Tarjan算法的原理和过程模拟的很详细. 转载大佬的博客https://www.cnblogs.com/JVxie/p/4854719.html 第二次更新,之前转载的博客虽然胜在详细,但 ...

  10. 404 Note Found -选题报告

    目录 NABCD分析引用 N(Need,需求): A(Approach,做法): B(Benefit,好处): C(Competitors,竞争): D(Delivery,交付): 初期 中期 个人贡 ...