浅谈VC++中的预编译(一)

来源:互联网 发布:pc3000数据恢复 编辑:程序博客网 时间:2024/05/22 01:33

浅谈VC++中的预编译(一)

From:

http://hi.baidu.com/exzz/blog/item/7b4d69181aa2a3b14bedbc57.html

 

一、预编译头文件说明

 

所谓头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(Windows.HAfxwin.H)预先编译,以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。这样可以加快编译速度,节省时间。

 

预编译头文件通过编译stdafx.cpp生成,以工程名命名,由于预编译的头文件的后缀是“pch”,所以编译结果文件是projectname.pch

 

编译器通过一个头文件stdafx.h来使用预编译头文件。stdafx.h这个头文件名是可以在project的编译设置里指定的。编译器认为,所有在指令#include "stdafx.h"前的代码都是预编译的,它跳过#include "stdafx. h"指令,使用projectname.pch编译这条指令之后的所有代码。

 

因此,所有的CPP实现文件第一条语句都是:#include "stdafx.h"

 

另外,每一个实现文件CPP都包含了如下语句:

 

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

这是表示,如果生成调试版本,要指示当前文件的名称。__FILE__是一个宏,在编译器编译过程中给它赋值为当前正在编译的文件名称。

 

vc.net默认情况下使用预编译头(/Yu),不明白的在加入新.h文件后编译时总出现fatal error C1010: 在查找预编译头指令时遇到意外的文件结尾的错误。解决方法是在在include头文件的地方加上#include "stdafx.h",或者打项目属性,找到“C/C++”文件夹,单击“预编译头”属性页。修改“创建/使用预编译头”属性为“不使用预编译头”。

 

二、C/C++头文件一览

 

C、传统 C++

#include <assert.h>    //设定插入点

#include <ctype.h>     //字符处理

#include <errno.h>     //定义错误码

#include <float.h>     //浮点数处理

#include <fstream.h>    //文件输入/输出

#include <iomanip.h>    //参数化输入/输出

#include <iostream.h>   //数据流输入/输出

#include <limits.h>    //定义各种数据类型最值常量

#include <locale.h>    //定义本地化函数

#include <math.h>     //定义数学函数

#include <stdio.h>     //定义输入/输出函数

#include <stdlib.h>    //定义杂项函数及内存分配函数

#include <string.h>    //字符串处理

#include <strstrea.h>   //基于数组的输入/输出

#include <time.h>     //定义关于时间的函数

#include <wchar.h>     //宽字符处理及输入/输出

#include <wctype.h>    //宽字符分类

 

标准 C++ (同上的不再注释)

#include <algorithm>    //STL 通用算法

#include <bitset>     //STL 位集容器

#include <cctype>

#include <cerrno>

#include <clocale>

#include <cmath>

#include <complex>     //复数类

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <ctime>

#include <deque>      //STL 双端队列容器

#include <exception>    //异常处理类

#include <fstream>

#include <functional>   //STL 定义运算函数(代替运算符)

#include <limits>

#include <list>      //STL 线性列表容器

#include <map>       //STL 映射容器

#include <iomanip>

#include <ios>       //基本输入/输出支持

#include <iosfwd>     //输入/输出系统使用的前置声明

#include <iostream>

#include <istream>     //基本输入流

#include <ostream>     //基本输出流

#include <queue>      //STL 队列容器

#include <set>       //STL 集合容器

#include <sstream>     //基于字符串的流

#include <stack>      //STL 堆栈容器    

#include <stdexcept>    //标准异常类

#include <streambuf>    //底层输入/输出支持

#include <string>     //字符串类

#include <utility>     //STL 通用模板类

#include <vector>     //STL 动态数组容器

#include <cwchar>

#include <cwctype>

 

using namespace std;

 

C99 增加

#include <complex.h>   //复数处理

#include <fenv.h>    //浮点环境

#include <inttypes.h>  //整数格式转换

#include <stdbool.h>   //布尔环境

#include <stdint.h>   //整型环境

#include <tgmath.h>   //通用类型数学宏

 

三、预处理的由来

 

C++的历史发展中,有很多的语言特征(特别是语言的晦涩之处)来自于C语言,预处理就是其中的一个。C++C语言那里把C语言预处理器继承过来(C语言预处理器,被Bjarne博士简称为Cpp,不知道是不是C Program Preprocessor的简称)。

 

四、常见的预处理功能

 

预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。

 

文件包含:#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。

条件编译:#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。

 

布局控制:#pragma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。

 

宏替换:#define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。

 

五、预处理指令

 

预处理指令的格式如下:

#directive tokens

 

#符号应该是这一行的第一个非空字符,一般我们把它放在起始位置。如果指令一行放不下,可以通过“/”进行控制,例如:

#define Error if(error) exit(1)

等价于

#define Error /

if(error) exit(1)

 

下面我们看一下常见的预处理指令:

#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格式的头文件早在989月份就被标准委员会抛弃了,我们应该紧跟标准,以适合时代的发展。其次,iostream.h只支持窄字符集,iostream则支持窄/宽字符集。还有,标准对iostream作了很多的改动,接口和实现都有了变化。最后,iostream组件全部放入namespace std中,防止了名字污染。

 

2<io.h>"io.h"的区别?

其实他们唯一的区别就是搜索路径不同:对于#include <io.h> ,编译器从标准库路径开始搜索对于#include "io.h" ,编译器从用户的工作路径开始搜索。

原创粉丝点击