c/c++中的预编译指令总结
预处理指令提供按条件跳过源文件中的节、报告错误和警告条件,以及描绘源代码的不同区域的能力。使用术语“预处理指令”只是为了与 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++中的预编译指令总结的更多相关文章
- 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#中的预编译指令介绍 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/C++中的预编译指令(转)
reference:https://blog.csdn.net/sunshinewave/article/details/51020421 程序的编译过程可以分为预处理.编译.汇编三部分,其中预处理是 ...
- C#中的预编译指令介绍[转]
原文链接 1.#define和#undef 用法: #define DEBUG #undef DEBUG #define告诉编译器,我定义了一个DEBUG的一个符号,他类似一个变量,但是它没有具体的值 ...
- c语言中条件编译相关的预编译指令
一. 内容概述 本文主要介绍c语言中条件编译相关的预编译指令,包括#define.#undef.#ifdef.#ifndef.#if.#elif.#else.#endif.defined. 二.条件编 ...
- C#预编译指令
近日工作涉及到于外部系统交互,对方提供接口:但是在双方系统未联调时,引用外部DLL,相关类实例化,提示异常错误(错误消息正常):后面操作无法进行,那如何写调试代码,即在调试时不运行某段代码,而在正式发 ...
随机推荐
- EasyUI tree 优化--点击文字折叠展开效果
$(function () { $('#tree_menu').tree({ onSelect: function (node) { if (node.state == "closed&qu ...
- linux ——使用find如何快速替换所有相同参数
在生成环境上有时候需要大规模修改某一配置里的参数,但是该参数存在多个地方,比如IP地址 端口 项目名等,特别是项目名称混乱想统一 find /项目地址 -type f |xargs grep &qu ...
- Gradle初使用
我以前一直使用Maven来构建工程,这两天突然发现gradle也非常好用,记录一下自己使用gradle的过程. Gradle的下载与配置 本次选择下载的是gradle3.5版本,没选最新的gradle ...
- 第五章—if语句
5-1 条件测试 :编写一系列条件测试:将每个测试以及你对其结果的预测和实际结果都打印出来.你编写的代码应类似于下面这样: car = 'subaru' print("Is car == ' ...
- Maven私有仓库搭建以及使用
一.使用Docker安装Nexus Docker search nexus docker pull docker.io/sonatype/nexus3 mkdir -p /usr/local/nexu ...
- mysql 数据库名含“-”
跨数据库操作时,用反引号即可: insert into `tmi-ds`.knn_test(imagedata) select imagedata from tmidb.imagetable wher ...
- java调试器
javac.exe是编译.java文件 java.exe是执行编译好的.class文件 javadoc.exe是生成Java说明文档 jdb.exe是Java调试器 javaprof.exe是剖析工具 ...
- UITableViewCell contentView layoutSubviews 死循环
发现一个问题,当在UITableViewCell 的 layoutSubviews 中修改 contentView 的frame时会产生死循环.该问题只会出现在iOS8中,iOS7与iOS9均没有问题 ...
- Codeforces Round #345 (Div. 1) C. Table Compression dp+并查集
题目链接: http://codeforces.com/problemset/problem/650/C C. Table Compression time limit per test4 secon ...
- .NET Core 控制台中文乱码问题!
class Program { static void Main(string[] args) { Encoding.RegisterProvider(CodePagesEncodingProvide ...