欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    《预处理器》PPT课件.ppt

    • 资源ID:5620293       资源大小:256.49KB        全文页数:39页
    • 资源格式: PPT        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    《预处理器》PPT课件.ppt

    第14章,预处理器,本章要点,预处理器的工作原理预处理指令宏定义条件编译,引言,指令如#define 和#include 等是由预处理器进行处理的,而预处理器是一个在编译前编辑C程序的软件.C语言(和 C+语言)因为依赖预处理器而不同于其他的编程语言。预处理器是一个强大的工具,但它同时也可能是许多难以发现的错误的根源。,14.1 预处理器的工作原理,预处理器查找以#开头的预处理指令.前面,我们已经遇到过#define 和#include指令.#define 指令定义一个宏(macro)即一个能够代表其它东西的名字,比如一个常量。预处理器会通过将宏的名字和它的定义存储在一起来响应#define指令。当这个宏在后面的程序中使用到时,预处理器“扩展”了宏,将宏替换为它所定义的值。,预处理器的工作原理,#include指令告诉预处理器打开一个特定的文件,将它的内容作为正在编译的文件的一部分“包含”进来。例如,下面一行:#include 指示预处理器打开一个名字为 stdio.h的文件,并将它的内容加到当前的程序中。,预处理器的工作原理,在编译过程中中,预处理器的角色如图所示:,预处理器的工作原理,预处理器的输入是一个 C语言程序,程序可能包含指令。预处理器会执行这些指令,并在处理过程中删除这些指令。预处理的输出是另一个C程序:原程序编辑后的版本。预处理器的输出被直接交给编译器。,预处理器的工作原理,第二章中的 celsius.c:/*Converts a Fahrenheit temperature to Celsius*/#include#define FREEZING_PT 32.0f#define SCALE_FACTOR(5.0f/9.0f)int main(void)float fahrenheit,celsius;printf(Enter Fahrenheit temperature:);scanf(%f,预处理器的工作原理,预处理过后为:Blank lineBlank lineLines brought in from stdio.hBlank lineBlank lineBlank lineBlank lineint main(void)float fahrenheit,celsius;printf(Enter Fahrenheit temperature:);scanf(%f,预处理器的工作原理,预处理器不仅仅是执行了指令,还做了一些其他的事情。特别值得注意的是,它将每一处注释都替换为一个空格字符。有一些预处理器还会进一步删除不必要的空白字符,包括在每一行开始用于缩进的空格符和制表符。在 C语言较早的时期,预处理器是一个单独的程序,并将它的输出提供给编译器。如今,预处理器通常和编译器集成在一起(为了提高编译的速度)。在理解上,将预处理器从编译器分开是比较有用的。,预处理器的工作方式,大多数编译器提供查看预处理输出的方法。一些编译器通过使用特定选项来产生预处理结果(如 gcc E)。其它一些编译环境带有类似集成预处理器的独立的程序。注意,预处理器仅知道少量 C语言的规则,因此,它在执行指令时非常有可能产生非法的程序。对于较复杂的程序,检查预处理器的输出可能是找到这类错误的有效途径。,14.2 预处理指令,大多数预处理指令属于下面 3种类型之一:宏定义。#define指令定义一个宏,#undef指令删除一个宏定义。文件包含。#include指令导致一个指定文件的内容被包含到程序中。条件编译。#if、#ifdef、#ifndef、#elif、#else和#endif指令可以根据测试的条件来将一段文本块包含到程序中或排除在程序之外。几条应用于所有指令规则:指令都以#开始。#符号不需要在一行的行首,只要它之前只有空白字符就行。在#后是指令名,接着是指令所需要的其他信息。在指令的符号之间可以插入任意数量的空格或横向制表符。例如,下面的指令是合法的:#define N 100,预处理指令,指令总是在第一个换行符处结束,除非明确地指明要继续。如果想在下一行继续指令,我们必须在当前行的末尾使用字符,例如:#define DISK_CAPACITY(SIDES*TRACKS_PER_SIDE*SECTORS_PER_TRACK*BYTES_PER_SECTOR)指令可以出现在程序中任何地方。我们通常将#define和#include指令放在文件的开始,其他指令则放在后面,甚至在函数定义的中间。注释可以与指令放在同一行。实际上,在一个宏定义的后面加一个注释来解释宏的意义是一种比较好的习惯:#define FREEZING_PT 32.0f/*freezing point of water*/,14.3 宏定义,我们从第 2章以来使用的宏被称为简单的宏,它们没有参数,预编译器也支持带参数的宏。简单的宏定义有如下格式:#define 标识符 替换列表替换列表是一系列的 C语言记号,包括标识符、关键字、数、字符常量、字符串字面量、运算符和标点符号。在文件后面的内容中,不管标识符在任何位置出现,预处理器都会用替换列表代替它。,14.3.1 简单的宏,不要在宏定义中放置任何额外的符号,否则它们会被作为替换列表的一部分。一种常见的错误是在宏定义中使用=,如:#define N=100/*WRONG*/int aN;/*becomes int a=100;*/在宏定义的末尾使用分号结尾是另一个常见错误,如:#define N 100;/*WRONG*/int aN;/*becomes int a100;*/编译器将会检测到绝大多数由多余符号所导致的错误。编译器会将每一处使用这个宏的地方标为错误,而不会直接找到错误的根源宏定义本身,因为宏定义已经被预处理器删除了。,简单的宏,简单的宏可以定义“明示常量manifest constants”#define STR_LEN 80#define TRUE 1#define FALSE 0#define PI 3.14159#define CR r#define EOS 0#define MEM_ERR Error:not enough memory,简单的宏,#define的优点:使程序更容易读。使程序更容易修改。避免前后不一致的输入错误,例如3.14159,误输入为 3.1416或 3.14195。可以对C语法做小的修改。#define BEGIN#define END#define LOOP for(;)对类型重命名。#define BOOL int控制条件编译。#define DEBUG,14.3.2 带参数的宏,带参数的宏定义有如下格式:#define 标识符(x1,x2,xn)替换列表 其中 x1,x2,xn是标识符(宏的参数)。在宏的名字和左括号之间必须没有空格。如果有空格,预处理器会认为是在定义一个简单的宏,其中(x1,x2,xn)是替换列表的一部分。,带参数的宏,带参数的宏举例:#define MAX(x,y)(x)(y)?(x):(y)#define IS_EVEN(n)(n)%2=0)调用这些宏:i=MAX(j+k,m-n);if(IS_EVEN(i)i+;宏替换后:i=(j+k)(m-n)?(j+k):(m-n);if(i)%2=0)i+;,带参数的宏,复杂的类似函数的宏:#define TOUPPER(c)(a 头提供了一个更容易移植的相似函数toupper。带参数的宏也可能具有空的参数列表:#define getchar()getc(stdin)空的参数列表不是一定确实需要,但可以使 getchar更像一个函数。,带参数的宏,使用带参数的宏替代实际的函数有两个优点:程序可能会稍微快些。一个函数调用在执行时通常会有些额外开销 存储上下文信息、复制参数的值等。而一个宏的调用则没有这些运行开销。宏会更“通用”。与函数的参数不同,宏的参数没有类型。只要预处理后的程序依然是合法的,宏可以接受任何类型的参数。带参数的宏也有一些缺点。编译后的代码通常会变大。每一处宏调用都会导致插入宏的替换列表,由此导致程序的源代码增加(因此编译后的代码变大)。当宏调用嵌套时,这个问题会相互叠加从而使程序更加复杂。n=MAX(i,MAX(j,k);/*预处理后*/n=(i)(j)(k)?(j):(k)?(i):(j)(k)?(j):(k);,14.3.3#运算符,宏定义可以包含两个运算符:#和#。编译器不会识别这两种运算符;相反,它们会在预处理时被执行。#运算符将一个宏的参数转换为字符串字面量。它仅允许出现在带参数的宏的替换列表中。#运算符有大量的用途,这里只来讨论其中的一种。假设我们决定在调试过程中使用PRINT_INT宏作为一个便捷的方法,来输出一个整型变量或表达式的值。#运算符可以使PRINT_INT为每个输出的值添加标签。,#运算符,改进后的 PRINT_INT:#define PRINT_INT(n)printf(#n=%dn,n)调用PRINT_INT(i/j);将转换为printf(i/j=%dn,i/j);编译器自动连接两个相邻的字符串字面量,因此上面语句等价为:printf(i/j=%dn,i/j);,14.3.4#运算符,#运算符可以将两个记号(例如标识符)“粘”在一起,成为一个记号。如果其中一个操作数是宏参数,“粘合”会在当形式参数被相应的实际参数替换后发生。使用#运算符的宏:#define MK_ID(n)i#n下面声明调用 MK_ID 三次:int MK_ID(1),MK_ID(2),MK_ID(3);预处理过后,该语句为:int i1,i2,i3;,#运算符,#运算符不属于预处理器经常使用的特性。考虑前面提到过的 MAX宏,当 MAX的参数有副作用时会无法正常工作;同时,由于参数类型的原因,一个max函数也是不够的。一种解决方法是用 MAX宏来写一个 max 函数,并使它展开后成为 max函数的定义。宏的参数将用于说明参数和返回值的类型。,#运算符,问题:如果我们是用宏来创建多个 max函数,程序将无法编译。(C语言不允许在同一文件中出现两个同名的函数。)为了解决这个问题,我们是用#运算符为每个版本的 max函数构造不同的名字。下面是宏的显示形式:#define GENERIC_MAX(type)type type#_max(type x,type y)return x y?x:y;对该宏的调用:GENERIC_MAX(float)预处理过后的代码为:float float_max(float x,float y)return x y?x:y;,14.3.5 宏的通用属性,同时适用于简单和带参数的宏的规则:宏的替换列表可以包含对另一个宏的调用,例如:#define PI 3.14159#define TWO_PI(2*PI)当预处理器在后面的程序中遇到 TWO_PI时,会将它替换成(2*PI)。预处理器会不断重新检查替换列表,直到将所有的宏名字都替换掉为止。,宏的通用属性,预处理器只会替换完整的记号,而不会替换记号的片断。因此,预处理器会忽略嵌在标识符名、字符常量、字符串字面量之中的宏名。例如:#define SIZE 256int BUFFER_SIZE;if(BUFFER_SIZE SIZE)puts(Error:SIZE exceeded);预处理过后:int BUFFER_SIZE;if(BUFFER_SIZE 256)puts(Error:SIZE exceeded);,宏的通用属性,一个宏定义的作用范围通常到出现这个宏的文件末尾。由于宏是由预处理器处理的,他们不遵从通常的范围规则。一个定义在函数中的宏并不是仅在函数内起作用,而是作用到文件末尾。宏不可以被定义两遍,除非新的定义与旧的定义是一样的。小的间隔上的差异是允许的,但是宏的替换列表(和参数,如果有的话)中的记号都必须一致。宏可以使用#undef指令“取消定义”。#undef指令有如下形式:#undef指令#undef 标识符#undef指令的一个用途是取消一个宏的现有定义,以便于重新给出新的定义。#undef N,14.3.6 宏定义中的圆括号,宏定义中的替换列表往往需要圆括号,以免发生意料之外的结果。如果宏的替换列表中有运算符,那么始终要将替换列表放在括号中:#define TWO_PI(2*3.14159)如果宏有参数,每次参数在替换列表中出现时都要放在圆括号中:#define SCALE(x)(x)*10)没有括号的话,将无法确保编译器会将替换列表和参数作为完整的表达式。编译器可能会不按我们期望的方式应用运算符的优先级和结合性规则。考虑下面的宏定义,其中的替换列表没有添加圆括号:#define TWO_PI 2*3.14159预处理过程中,语句:conversion_factor=360/TWO_PI;成为:conversion_factor=360/2*3.14159;除法会在乘法之前完成,产生期望之外的结果。,宏定义中的圆括号,当宏有参数时,仅给替换列表添加圆括号是不够的。参数的每一次出现都要添加圆括号。#define SCALE(x)(x*10)在预处理过程中,语句:j=SCALE(i+1);变为:j=(i+1*10);由于乘法的优先级比加法高,这条语句等价于:j=i+10;,14.4 条件编译,C语言的预处理器可以识别大量用于支持条件编译的指令。这个功能能够使预处理器根据条件测试结果来决定包含或排除程序中的一些片断。,14.4.1#if指令和#endif指令,假如我们正在调试一个程序,我们想要程序显示出特定变量的值,因此将 printf函数调用添加到程序中重要的部分。一旦找到错误,经常需要保留这些 printf函数调用,以备以后使用,条件编译允许我们保留这些调用,但是让编译器忽略它们。首先定义一个宏,并给它一个非 0的值:#define DEBUG 1接下来,我们要在每组 printf函数调用的前后加上#if和#endif:#if DEBUGprintf(Value of i:%dn,i);printf(Value of j:%dn,j);endif,#if指令和#endif指令,在预处理过程中,#if指令会测试 DEBUG的值。由于 DEBUG的值非0,因此预处理器会将这两个 printf函数调用保留在程序中(但#if和#endif行会消失)。如果我们将 DEBUG的值改为 0并重新编译程序,预处理器则会将这 4行代码都删除。我们可以将#if-#endif保留在最终的程序中,这样如果程序在运行时出错,可以继续产生这些诊断信息(将 DEBUG改为 1并重新编译)。,#if指令和#endif指令,一般来说,#if指令的格式如下:#if constant-expression#endif当预处理器遇到#if指令时,会计算常量表达式。如果表达式的值为0,那么在#if与#endif之间的行将在预处理过程中从程序中删除。否则,这些在#if和#endif之间的行会被保留在程序中,并继续被编译器处理这时#if和#endif对程序没有任何影响。,#if指令和#endif指令,对于没有定义过的标识符,#if指令会把它当作是值为 0的宏对待。如果我们没有定义 DEBUG,则测试:#if DEBUG将会失败(但不会产生错误消息)。而测试:#if!DEBUG则会成功。,36,defined运算符,14.3节介绍了#和#运算符,还有一种预处理器运算符:defined如果标识符是一个定义过的宏则返回1,否则返回0。defined运算符通常与#if指令结合使用。#if defined(DEBUG)#endif仅当 DEBUG被定义成宏时,#if和#endif之间的代码会被保留在程序中DEBUG两侧的括号不是必需的,因此可以简单写成:#if defined DEBUG也不必给 DEBUG 一个值:#define DEBUG,14.4.3#ifdef指令和#ifndef指令,#ifdef指令测试一个标识符是否已经定义为宏:#ifdef identifier其效果与此语句相同:#if defined(identifier)#ifndef 指令测试一个标识符当前是否未被定义为宏:#ifndef identifier其效果与此语句相同:#if!defined(identifier),14.4.4#elif指令和#else指令,#if,#ifdef,和#ifndef 可以像普通if语句一样嵌套。当出现嵌套时,采用缩进来表示不同的嵌套层次是比较好的实践。某些程序员在每个#endif后面留注释来表明所匹配的测试条件:#if DEBUG#endif/*DEBUG*/#elif指令和#else指令可以与#if指令、#ifdef指令和#ifndef指令组合使用,来测试一系列条件:#if expr1当表达式 1非 0时需要包含的代码#elif expr2当表达式 1为 0但表达式 2非 0时需要包含的代码#else其他情况下需要包含的代码#endif在#if指令和#endif指令之间可以有多个#elif指令,但最多只能有一个#else指令。,

    注意事项

    本文(《预处理器》PPT课件.ppt)为本站会员(小飞机)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开