零点起飞学c++之不是代码的代码——预处理

上传人:mg****85 文档编号:50421817 上传时间:2018-08-08 格式:PPTX 页数:36 大小:215.21KB
返回 下载 相关 举报
零点起飞学c++之不是代码的代码——预处理_第1页
第1页 / 共36页
零点起飞学c++之不是代码的代码——预处理_第2页
第2页 / 共36页
零点起飞学c++之不是代码的代码——预处理_第3页
第3页 / 共36页
零点起飞学c++之不是代码的代码——预处理_第4页
第4页 / 共36页
零点起飞学c++之不是代码的代码——预处理_第5页
第5页 / 共36页
点击查看更多>>
资源描述

《零点起飞学c++之不是代码的代码——预处理》由会员分享,可在线阅读,更多相关《零点起飞学c++之不是代码的代码——预处理(36页珍藏版)》请在金锄头文库上搜索。

1、第22章 不是代码的代码预处理 预处理是指在进行编译的第一遍扫描(词法扫描和语法分 析)之前所做的工作。它是C+语言的一个重要功能,由 预处理程序负责完成。合理地使用预处理不仅便于阅读、 修改、移植和调试,也有利于模块化设计。本章将详细介 绍常用的几种预处理功能。本章的目的是让读者学会编写 健壮、可移植程序的重要方法,它是提高程序执行效率的 重要手段。22.1 什么是预处理 预处理发生在编译的第一遍扫描之前,它是程序员写在程 序代码中的提供给预处理器(preprocessor)的指令,而不 是程序本身的语句。预处理指令以#号开头,所有指令必 须写在单独的一行中,不需要加结尾的语句结束符号“;”

2、。 常见的预处理指令有文件包含,条件编译、布局控制和宏 替换等4种。【示例22-1】 #include预处理指令的用法。#include /include预处理指令 int main(void) cout #include “my.h“两种形式的区别在于: 用来引用标准库头文件,编译器将只搜索包含标准库头文件 的目录; “常用来引用自定义的头文件,搜索正在编译的源文件所在的 目录,找不到时再搜索包含标准库头文件的目录。【示例22-2】 演示#include预处理指令的使用方法。 #include #include #include “d:/project/cpp/include/my1.h“

3、#include “/include/my2.h“ 分析:该示例的前两条语句利用include指令将系统的标准 I/O库文件引入,后两条语句将自定义的头文件引入。 该示例中还有两个地方需要注意:1与的区 别 两种写法都是从标准库目录中引入iostream的支持,但是 前者是新形式,后者是旧形式,两者有很大不同。首先,. h格式的头文件早在1998年9月份就被标准委员会抛弃了。 其次,iostream.h只支持窄字符集,iostream则支持窄/宽字 符集。标准也对iostream做了很多的改动,接口和实现都 有了变化。最后,iostream组件全部放入namespace std中, 防止了名字

4、污染。2路径 如果头文件在标准库或当前目录下,则不需要加路径:否 则就应该加上路径,明确指出文件所在的位置。加路径时 可以是绝对路径,也可以是以当前目录为起点的相对路 径。但是需要注意的是路径中一定要用“/”来代替“”。 注意:C+并没有为#include提供替代形式,但是 namespace提供了一种作用域机制,它能以某种方式支持 组合,利用它可以改善#include的行为方式,但还是无法 取代#include。22.2.2 布局控制#pragma 布局控制指令是#pragma,它是所有的预处理指令中最复 杂的一条指令。它的作用是设定编译器的状态或者指示编 译器完成一些特定的动作,对编译器进

5、行配置,针对所使 用的平台和编译器的不同而有所不同。这意味着#pragma 指令对每个编译器给出了一个方法,在保持与C和C+语 言完全兼容的情况下,给出主机或操作系统专有的特征。 格式如下: #pragma parameter 其中parameter为参数,指明要对系统的哪方面特征进行重 新布局。下面将讲解一些常用参数的用法。1message参数 该参数能够在编译窗口中输出信息,使用方法为: #pragma message(information) 当编译器遇到这条指令时就在编译窗口中输出括号中的内 容。2code_seg参数该参数用来设置程序中函数在.obj文件中存放的代码段,多用于驱动 程

6、序的开发中,格式如下所示。#pragma code_seg(push|pop,identifier,“segment-name“,“segment - class“)函数在.obj文件中默认的存放段为.text,如果code_seg不带参数,则函 数就存放在.text段中。 push为可选参数,表示将一个记录放到内部编译器的堆栈中,它可以 为一个标识符或者段名。 pop为可选参数,表示将一个记录从堆栈顶端弹出,该记录可以为一 个标识符或者段名。 identifier为可选参数,表示当使用push指令时,为压入堆栈的记录指 派的一个标识符,当该标识符被删除的时候和其相关的堆栈中的记录 将被弹出堆

7、栈。 segment-name为可选参数,表示函数存放的段名。3once参数 该参数比较常用,只要在头文件的最开始加入这条指令就 能够保证头文件仅被编译一次,格式如下: #pragma once 该预编译指令用来防止某个头文件被多次包含。它与编译 器相关,因此可移植性差。4hdrstop参数 该参数表示预编译头文件到此为止,后面的头文件不进行 预编译,格式如下: #pragma hdrstop 虽然预编译头文件可以加快链接的速度,但如果所有头文 件都进行预编译,可能会占用太多磁盘空间。这时就可以 使用该参数排除一些头文件,不进行预编译。5pack参数 该参数用来改变字节对齐方式,格式如下: #

8、pragma pack(n) 其中,n为对齐方式。【示例22-3】 修改对齐方式为一字节对齐。 分析:在未修改对齐方式前,结构体实际用掉了8字节的 空间,但其真正的大小只有5字节。用pack参数将对齐方 式改为了一字节对齐后,ex2实际所用掉的空间与其实际 大小就变为一致了。另一个需要注意的地方是,修改对齐 方式的前后一定要注意保留原来的设置,这点通过用push 和pop来实现。6comment参数该参数将一个注释记录放入对象文件或可执行文件中,格式如下:#pragma comment( comment-type ,“comment-string“ ) 其中,comment-type是预定义的

9、标识符,表示注释的类型,可以是 compiler、exestr、lib、linker等4种之一。comment-string是为comment- type提供附加信息的字符串。 comment-type的4种类型释意如下: compiler:放置编译器的版本或名字到对象文件中,该选项可被linker 忽略; exestr:在以后的版本将被取消; lib:放置库搜索记录到对象文件中,comment-string指定要Liner搜索 的lib的名称和路径; linker:连接选项。【示例22-4】 comment参数的使用举例。 #pragma comment(lib,“ws2_32“); 分析:

10、表示将winsock2.lib库文件包含进来。7warning参数 该参数用于禁用某些警告,格式如下: #pragma warning (disable:warning-list) #pragma warning (once:warning-list) #pragma warning (error:warning-list) 其中,disable表示禁用某些警告,once表示某警告仅警告 一次,error表示把该警告作为错误处理。warning-list是警 告的列表。【示例22-5】 对警告244的处理方法,244是一条警告类型转换中可能会丢失精度的警 告。 分析:该实例给出了pragma的

11、三种使用方式,在不使用disable的情况下, 编译器会提示:warning C4244: = : conversion from float to int, possible loss of data warning C4244: = : conversion from double to float, possible loss of data表示编译器发现了潜在丢失精度的危险。如果使用disable,则编译器将不 会给出任何警告。如果使用once,则编译器将只对a=x警告一次,而对 x=y则不给出警告。如果使用error,则编译器将输出如下:error C4244: = : conver

12、sion from float to int, possible loss of data error C4244: = : conversion from double to float, possible loss of data这表示编译器将警告244作为了错误来处理。说明:错误与警告的区别在于,如果是错误,编译器将不允 许链接,而警告并不影响链接。懂得这一点就会明白error的好 处,它使程序的检查变得更加严格。 此外还可以使用push和pop参数,分别表示保存警告信息的现有 的警告状态和弹出最后一个警告信息的状态。格式如下所示。#pragma warning( push ) #pra

13、gma warning( push,n) #pragma warning( pop )其中,n表示警告级别,第二条语句表示保存所有警告信息的现 有警告状态,并且把全局警告等级设定为n。22.2.3 宏替换#define 宏就是在源程序中用一个标识符来表示一个字符串,被定 义为“宏”的标识符称为“宏名”。在编译预处理时,对程序 中任何出现的“宏名”,都用宏定义中的字符串去代换,这 称为“宏替换”或“宏展开”。 #define macro_name string 其中,macro_name是宏名,string是字符串,可以实现符 号常量、函数功能、重新命名等功能。编译时,预处理器 只是简单地将ma

14、cro_name替换为string即可,不作任何检 查。如果有错误,只能在编译已被宏展开后的程序时发 现。 结束宏的作用域使用下述指令。 #undef macro_name C+中的宏分为有参数和无参数两种。1无参数宏的定义无参数宏的宏名后不需要带参数,其定义的格式如下所示。#define macro_name stringstring是一个字符串,串中没有任何参数。 例如,下述3个宏的定义。#define _PI_ 3.14159 #define _FILE_NAME_ “my.dat“ #define real double这里定义了3个宏_PI_、_FILE_NAME_和real,分别定

15、义了圆周 率、文件名和实数类型的宏。2有参数宏的定义 有参数宏的宏名后需要带参数,其定义的格式如下所示。 #define macro_name(parameter_list) string 其中,括号内是参数列表,string串是一个对参数进行处 理的语句,类似一个函数。【示例22-6】 定义max宏。 该示例中定义了max宏,该宏返回两个数中较大的一个。 最后一条语句表示结束宏max的作用范围,即撤销该宏的 定义。 此外,还有下述一些预定义的宏可供使用。 _FILE_:正在编译的文件名字; _LINE_:正在编译的文件当前行号; _DATE_:编译时的日期字符串; _TIME_:编译时的时间

16、字符串。22.2.4 条件编译 条件编译指令可以对程序源代码的各部分有选择地进行编 译,该过程就称为条件编译。常见的条件编译指令有#if、 #elif、#else、#ifndef、#ifdef、#endif等,它们主要用来在 编译时进行选择,屏蔽掉一些代码。它的使用方式主要有 下述3种形式。1根据常量的值选择要编译的程序 段这种形式的格式如下所示:#if const_exp1 ./程序段1 #elif const_exp2 ./程序段2 #else ./程序段3 #endif 如果常量表达式const_exp1的值为真(非0),则对程序段1进行编译 ;否则,如果const_exp2的值为真,则

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 科普知识

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号