第八章编译预处理.docx

上传人:王** 文档编号:520008 上传时间:2023-11-13 格式:DOCX 页数:5 大小:21.63KB
下载 相关 举报
第八章编译预处理.docx_第1页
第1页 / 共5页
第八章编译预处理.docx_第2页
第2页 / 共5页
第八章编译预处理.docx_第3页
第3页 / 共5页
第八章编译预处理.docx_第4页
第4页 / 共5页
第八章编译预处理.docx_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《第八章编译预处理.docx》由会员分享,可在线阅读,更多相关《第八章编译预处理.docx(5页珍藏版)》请在优知文库上搜索。

1、第八章编译预处理第一节宏定义大家好,上一节咱们讲的是“变量的存储和引用,内部和外部函数”我们主要是围绕着下列话题进行讲解:(1)变量的存储类别(2)局部变量的存储方式(3)全局变量跨文件引用(4)函数的跨文件调用(5)StatiC关键字用法总结:本节是新的一章的第一节,我们围绕如下话题来讲解:(1)不带参数的宏定义(2)带参数的宏定义大家回忆一下老师以往讲解的内容:一个项目,可以由一个或者多个源文件组成,一个项目,咱们可以通过编译、链接最终形成一个可执行文件。那么这个编译,是一个一个的源文件也就是这里的.cpp文件单位进行的,每个源文件,都会编译成一个目标文件(.。也可能是obj,这个跟操作系

2、统有关),那如果源文件有几个,则可能就编译生成了几个目标文件,然后将这些目标文件进行链接,形成最终的一个一个的可执行文件。那么这个编译都干了什么事,笼统的说:词法,语法分析,目标代码生成,优化之类的一些东西。这个编译我们可以拆开来看它也是干了好几个事的,一般来讲他会干这么几个事:a)预处理:b)编译:词法,语法分析,目标代码生成,优化c)汇编:产生.0(.obj)目标文件;大家也不用深究这几个词是啥意思。老师本节课重点要说这个“预处理”,这个预处理是干什么的呢?咱们在源程序.cpp中加入一些特殊的代码(特殊命令),这些特殊代码有一些特殊能力,提供一些特殊功能,编译系统会先对这些特殊代码做处理,

3、这个就叫“预处理”,处理的结果再和源程序代码一起进行上边步骤b)的编译,汇编这一系列操作。C语言一般提供三种预处理功能,1:宏定义,2:文件包含,3:条件编译,我们本节课讲解“宏定义”;这三种功能也是通过在程序代码中写代码来实现,只不过这些代码比较特殊,都是用#开头。一:不带参数的宏定义;不带参数的宏定义是用来干嘛的呢?用一个指定的标识符来代表一个字符串,一般形式:#define标识符字符串标识符也叫宏名比如:#definePl3.作用:用Pl来代替“3.”这个字符串,程序源码中,我们写的是Pl(也就是一般形式中的标识符),在编译预处理时,所有在该#加由优之后的Pl都会被替换成“3.”;好处:

4、a)用一个简单的名字代替一个长字符串,所以这个标识符也被称为宏名。在预编译时将宏名替换成字符串的过程称为“宏展开二#define就是宏定义命令;b)增加了修改的方便性,为修改提供极大便利,这种能力被用的很频繁,如果Pl不等于3.14了,而是等于2.58了,是不是我只需要修改一行,整个程序就都等于被替换成成2.58了;这也叫提高了程序的可移植性;演示:#definePl3.intmain()(floatftmp;ftmp=2*PI;printf(ftmp=%fr,ftmp);)说明:实际上宏展开时,Pl就直接被替换成了3并不做语法检杳,所以替换完了后直接参与乘法运算,也就是ftmp=2*Pl;就

5、#1当于ftmp=2*3.;说明:(1)宏名一般大写字母表示,这是一种习惯,建议大家遵照这个习惯。(2)宏定义不是C语句,不必在行末加分号,如果加分号则连分号一起被替换了;#definePl3.;ftmp=2*Pl;这还好,不报错,这相当于ftmp=2*3.;ftmp=Pl*2;这就报语法错了。这相当于ftmp=3.;*2;(3)Vdefine命令出现在程序中函数的外面,宏名的有效范围是#define之后到本源文件结束,不能跨文件使用,如果在另外一个文件中使用,则需要在另外一个文件中也做相同定义,或者把这些定义放到一个公共文件里,并用下节课我们要讲解的#访(把这个公共文件包含到每个源文件中去;

6、一般来讲,#define命令都写在文件开头,函数之前;(4)可以用Jndef命令终止宏定义的作用域,这个用的相对比较少,大家先知道,以后遇到再说;演示如下:ftdefinePl3.intmain。主函数(floatftmp;ftmp=Pl*2;printf(ftmp=%fr,ftmp);Printf(断点在这里”);return0;)ftundefPlvoidfuncl()(floatftmp;ftmp=Pl*2;)(5)用#(区进行宏定义时,还可以引用己定义的宏,可以层层置换演示:#definePl3.#defineDPI2*Pl#defineDPICPIPl*DPIintmain。主函数(

7、floatftmp;ftmp=Pl*2;ftmp=DPI;ftmp=DPICPI;)宏展开之后:DPl被替换成2*3.,DPICPI被替换成3.*2*3.;(6)字符串内的字符,即便与宏名相同,也不进行替换:接上例演示:charstmp100=DPICPI;这里的DPICPI不能被替换二:带参数的宏定义;前面我们讲的不带参数的宏定义,只是进行简单的字符串替换,那这里要讲解的带参数的宏定义,就不是进行简单的字符串替换了,还要进行参数替换,一般形式如下:#define宏名(参数表)字符串也是用右边的“字符串”代替“宏名(参数表),但具体怎么替换,咱们后边详细讲;和不带参数的宏定义比,这里多了个参数

8、表。在字符串中,一般都会包含参数表中所指定的参数演示:#defineS(a,b)a*bintArea=S(3,2);在程序中,我们用了宏S,系统是怎么替换的呢?在程序中用了S(3,2),把3,2分别代替宏定义中的形式参数a,b,最终用3*2替换了S2);所以等价于intArea=3*2;咱们刚才说了,一般字符串中都会包含参数表中所指定的参数,但不包含也可以,但你若不包含,你通过参数表传进去这个参数干啥,不是没啥意义吗!比如#defineS(a,b)aintArea=S(3,2);总结:带参数的宏定义是这样展开置换的:对一般格式中这个字符串,要从左到右处理;如果字符串中有宏名后列出的形参比如(a

9、,b),则将程序语句中相应的实参(可以是常量,变量或者表达式)代替形参,如果字符串中的字符不是参数字符,则保留,比如上边a*b中的*;演示:#definePl3.ftdefineS(r)Pl*r*rintmain。主函数(floatarea;area=S(3.6);)说明:a)如果输入S(l+5)代替后变成:Pl*1+5*1+5;,这肯定不对,咱们的原意是代替后变成Pl*(1+5)*(1+5)为解决这个问题,我们要在形式参数外面加一个括号也就是:ftdefineS(r)Pl*(r)*(r)这样才能展开成Pl*(1+5)*(1+5)b)宏定义时,宏名和带参数的括号之间不能加空格,否则,空格以后的

10、字符都作为替代字符串的一部分了;比如如果如下定义:ftdefineS(r)Pl*(r)*(r)那这成啥了,S成为了不带参数的宏定义,代表字符串rt(r)PI*(r)*(r,这显然不对嘛;大家是不是感觉带参数的宏和函数挺像的,容易区分不开;宏也有实参形参,但他们还是有很不相同的地方:(1)函数调用是先求出实参表达式的值,然后带入形参,带参宏只进行简单的字符替换,宏展开时并不求值,比如上边的S(l+5),宏展开时并不求1+5的值,只是原样用实参替换掉形参。(2)函数调用是在程序运行时处理,分配临时内存。宏展开是在编译时进行的,展开时不分配内存单元,也不存在值传递的概念,当然也没有返回值的这个说法;

11、(3)宏的参数没有类型这个说法,只是个符号,展开时带入指定字符;#defineS(r)Pl*(r)*(r),比如这个r,并不是个类型;(4)使用宏次数多时,宏展开后源程序长,每展开一次都是程序增长,函数调用不会使源程序变长。(5)宏替换只占编译时间,不占运行时间,而函数调用占运行时间(分配内存,传递参数,执行函数体,返回值等等);有时候会用宏替换一些很复杂的语句,比如如下相对复杂一点的,求X和y的最大值#defineMAX(x,y)(x)(y)?(x):(y)调用的时候intresult=MAX(3,4);还有能代替多行语句的:末尾,老师讲过。这种用法在一定程度上能简化程序书写。#defineMACROTESTdoprintf(testn);while(0)宏这个东西,我们自己写代码的时候,可能用的还不太多,但有些人是频繁的使用的,比如大家有机会读读nginx开源代码,或者读一些跨平台的源码的时候,宏用的还是很多的;大家目前先掌握这么多,以后遇到更复杂的,再慢慢研究。这节课咱们就先到这,下次见。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 数据结构与算法

copyright@ 2008-2023 yzwku网站版权所有

经营许可证编号:宁ICP备2022001189号-2

本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!