《预处理器》PPT课件.ppt
《《预处理器》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《预处理器》PPT课件.ppt(39页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第第14章章l 本章要点引言引言v指令如指令如#define和和#include等是由预处理器进行处理的,等是由预处理器进行处理的,而预处理器是一个在编译前编辑而预处理器是一个在编译前编辑C程序的软件程序的软件.vC语言(和语言(和C+语言)因为依赖预处理器而不同于其他的编语言)因为依赖预处理器而不同于其他的编程语言。程语言。v预处理器是一个强大的工具,但它同时也可能是许多难以发预处理器是一个强大的工具,但它同时也可能是许多难以发现的错误的根源。现的错误的根源。14.1预处理器的工作原理预处理器的工作原理v预处理器查找以预处理器查找以#开头的预处理指令开头的预处理指令.v前面,我们已经遇到过前
2、面,我们已经遇到过#define和和#include指令指令.v#define指令定义一个指令定义一个宏(宏(macro)即一个能够代表其即一个能够代表其它东西的名字,比如一个常量。它东西的名字,比如一个常量。v预处理器会通过将宏的名字和它的定义存储在一起来响应预处理器会通过将宏的名字和它的定义存储在一起来响应#define指令。指令。v当这个宏在后面的程序中使用到时,预处理器当这个宏在后面的程序中使用到时,预处理器“扩展扩展”了宏,了宏,将宏替换为它所定义的值。将宏替换为它所定义的值。预处理器的工作原理预处理器的工作原理v#include指令告指令告诉预处诉预处理器打开一个特定的文件,将它的
3、理器打开一个特定的文件,将它的内容作内容作为为正在正在编译编译的文件的一部分的文件的一部分“包含包含”进进来。来。v例如,下面一行:例如,下面一行:#includev指示指示预处预处理器打开一个名字理器打开一个名字为为的文件,并将它的内容加到的文件,并将它的内容加到当前的程序中。当前的程序中。预处理器的工作原理预处理器的工作原理v在编译过程中中,预处理器的角色如图所示:在编译过程中中,预处理器的角色如图所示:预处理器的工作原理预处理器的工作原理v预处理器的输入是一个预处理器的输入是一个C语言程序,程序可能包含指令。语言程序,程序可能包含指令。v预处理器会执行这些指令,并在处理过程中删除这些指令
4、。预处理器会执行这些指令,并在处理过程中删除这些指令。v预处理的输出是另一个预处理的输出是另一个C程序:原程序编辑后的版本。程序:原程序编辑后的版本。v预处理器的输出被直接交给编译器。预处理器的输出被直接交给编译器。预处理器的工作原理预处理器的工作原理v第二章中的第二章中的:/*ConvertsaFahrenheittemperaturetoCelsius*/#include#defineSCALE_FACTOR(5.0f/9.0f)intmain(void)floatfahrenheit,celsius;printf(EnterFahrenheittemperature:);scanf(%f
5、,&fahrenheit);celsius=(fahrenheit-FREEZING_PT)*SCALE_FACTOR;printf(Celsiusequivalentis:%.1fn,celsius);return0;预处理器的工作原理预处理器的工作原理v预处理过后为预处理过后为:Blank lineBlank lineLines brought in from Blank lineBlank lineBlank lineBlank lineintmain(void)floatfahrenheit,celsius;printf(EnterFahrenheittemperature:);sca
6、nf(%f,&fahrenheit);celsius=(fahrenheit-32.0f)*(5.0f/9.0f);printf(Celsiusequivalentis:%.1fn,celsius);return0;预处理器的工作原理预处理器的工作原理v预处理器不仅仅是执行了指令,还做了一些其他的事情。预处理器不仅仅是执行了指令,还做了一些其他的事情。v特别值得注意的是,它将每一处注释都替换为一个空格字符。特别值得注意的是,它将每一处注释都替换为一个空格字符。v有一些预处理器还会进一步删除不必要的空白字符,包括在有一些预处理器还会进一步删除不必要的空白字符,包括在每一行开始用于缩进的空格符和制
7、表符。每一行开始用于缩进的空格符和制表符。v在在C语言较早的时期,预处理器是一个单独的程序,并将它语言较早的时期,预处理器是一个单独的程序,并将它的输出提供给编译器。的输出提供给编译器。v如今,预处理器通常和编译器集成在一起如今,预处理器通常和编译器集成在一起(为了提高编译的为了提高编译的速度速度)。v在理解上,将预处理器从编译器分开是比较有用的。在理解上,将预处理器从编译器分开是比较有用的。预处理器的工作方式预处理器的工作方式v大多数编译器提供查看预处理输出的方法。大多数编译器提供查看预处理输出的方法。v一些编译器通过使用特定选项来产生预处理结果(如一些编译器通过使用特定选项来产生预处理结果
8、(如gccE)。v其它一些编译环境带有类似集成预处理器的独立的程序。其它一些编译环境带有类似集成预处理器的独立的程序。v注意,预处理器仅知道少量注意,预处理器仅知道少量C语言的规则,因此,它在执行语言的规则,因此,它在执行指令时非常有可能产生非法的程序。指令时非常有可能产生非法的程序。v对于较复杂的程序,检查预处理器的输出可能是找到这类错对于较复杂的程序,检查预处理器的输出可能是找到这类错误的有效途径。误的有效途径。14.2预处理指令预处理指令v大多数预处理指令属于下面大多数预处理指令属于下面3种类型之一种类型之一:宏定义。宏定义。#define指令定义一个宏,指令定义一个宏,#undef指令
9、删除一个宏定义。指令删除一个宏定义。文件包含。文件包含。#include指令导致一个指定文件的内容被包含到程序中。指令导致一个指定文件的内容被包含到程序中。条件编译。条件编译。#if、#ifdef、#ifndef、#elif、#else和和#endif指令可以根指令可以根据测试的条件来将一段文本块包含到程序中或排除在程序之外。据测试的条件来将一段文本块包含到程序中或排除在程序之外。v几条应用于所有指令规则:几条应用于所有指令规则:指令都以指令都以#开始。开始。#符号不需要在一行的行首,只要它之前只有空白符号不需要在一行的行首,只要它之前只有空白字符就行。在字符就行。在#后是指令名,接着是指令所
10、需要的其他信息。后是指令名,接着是指令所需要的其他信息。在指令的符号之间可以插入任意数量的空格或横向制表符。例如,在指令的符号之间可以插入任意数量的空格或横向制表符。例如,下面的指令是合法的:下面的指令是合法的:#define N100预处理指令预处理指令v指令总是在第一个换行符处结束,除非明确地指明要继续。如果想在下指令总是在第一个换行符处结束,除非明确地指明要继续。如果想在下一行继续指令,我们必须在当前行的末尾使用一行继续指令,我们必须在当前行的末尾使用字符,例如:字符,例如:#defineDISK_CAPACITY(SIDES*TRACKS_PER_SIDE*SECTORS_PER_TR
11、ACK*BYTES_PER_SECTOR)v指令可以出现在程序中指令可以出现在程序中任何地方任何地方。我们通常将。我们通常将#define和和#include指令指令放在文件的开始,其他指令则放在后面,甚至在函数定义的中间。放在文件的开始,其他指令则放在后面,甚至在函数定义的中间。v注释可以与指令放在同一行。实际上,在一个宏定义的后面加一个注释注释可以与指令放在同一行。实际上,在一个宏定义的后面加一个注释来解释宏的意义是一种比较好的习惯:来解释宏的意义是一种比较好的习惯:#defineFREEZING_PT32.0f/*freezingpointofwater*/14.3宏定义宏定义v我们从第
12、我们从第2章以来使用的宏被称为简单的宏,它们没有参数,章以来使用的宏被称为简单的宏,它们没有参数,预编译器也支持带参数的宏。预编译器也支持带参数的宏。v简单的宏定义有如下格式:简单的宏定义有如下格式:#define标识标识符符替替换换列表列表v替换列表替换列表是一系列的是一系列的C语言记号,包括标识符、关键字、数、语言记号,包括标识符、关键字、数、字符常量、字符串字面量、运算符和标点符号。字符常量、字符串字面量、运算符和标点符号。v在文件后面的内容中,不管在文件后面的内容中,不管标识符标识符在任何位置出现,预处理在任何位置出现,预处理器都会用器都会用替换列表替换列表代替它。代替它。14.3.1
13、简单的宏简单的宏v不要在宏定义中放置任何额外的符号,否则它们会被作为替换列表的一不要在宏定义中放置任何额外的符号,否则它们会被作为替换列表的一部分。部分。v一种常见的错误是在宏定义中使用一种常见的错误是在宏定义中使用=,如,如:#defineN=100/*WRONG*/intaN;/*becomesinta=100;*/v在宏定义的末尾使用分号结尾是另一个常见错误,如:在宏定义的末尾使用分号结尾是另一个常见错误,如:#defineN100;/*WRONG*/intaN;/*becomesinta100;*/v编译器将会检测到绝大多数由多余符号所导致的错误。编译器将会检测到绝大多数由多余符号所导
14、致的错误。v编译器会将每一处使用这个宏的地方标为错误,而不会直接找到错误的编译器会将每一处使用这个宏的地方标为错误,而不会直接找到错误的根源根源宏定义本身,因为宏定义已经被预处理器删除了。宏定义本身,因为宏定义已经被预处理器删除了。简单的宏简单的宏v简单的宏可以定义简单的宏可以定义“明示常量明示常量manifestconstants”#defineSTR_LEN80#defineTRUE1#defineFALSE0#defineCRr#defineEOS0#defineMEM_ERRError:notenoughmemory简单的宏简单的宏v#define的的优优点:点:使程序更容易使程序更容
15、易读读。使程序更容易修改。使程序更容易修改。避免前后不一致的避免前后不一致的输输入入错误错误,例如,例如,误输误输入入为为或或。v可以可以对对C语语法做小的修改。法做小的修改。#defineBEGIN#defineEND#defineLOOPfor(;)v对类型重命名。对类型重命名。#defineBOOLintv控制条件编译。控制条件编译。#defineDEBUG14.3.2带参数的宏带参数的宏v带参数的宏定义有如下格式:带参数的宏定义有如下格式:#define标识符标识符(x1,x2,xn)替换列表替换列表其中其中x1,x2,xn是标识符是标识符(宏的参数宏的参数)。v在宏的名字和左括号之间
16、必须没有空格。在宏的名字和左括号之间必须没有空格。v如果有空格,预处理器会认为是在定义一个简单的宏,其中如果有空格,预处理器会认为是在定义一个简单的宏,其中(x1,x2,xn)是替换列表的一部分。是替换列表的一部分。带参数的宏带参数的宏v带参数的宏举例:带参数的宏举例:#defineMAX(x,y)(x)(y)?(x):(y)#defineIS_EVEN(n)(n)%2=0)v调用这些宏:调用这些宏:i=MAX(j+k,m-n);if(IS_EVEN(i)i+;v宏替换后:宏替换后:i=(j+k)(m-n)?(j+k):(m-n);if(i)%2=0)i+;带参数的宏带参数的宏v复杂的类似函数
17、的宏复杂的类似函数的宏:#defineTOUPPER(c)(a=(c)&(c)=z?(c)-a+A:(c)v头提供了一个更容易移植的相似函数头提供了一个更容易移植的相似函数toupper。v带参数的宏也可能具有空的参数列表:带参数的宏也可能具有空的参数列表:#definegetchar()getc(stdin)v空的参数列表不是一定确实需要,但可以使空的参数列表不是一定确实需要,但可以使getchar更像更像一个函数。一个函数。带参数的宏带参数的宏v使用带参数的宏替代实际的函数有两个优点:使用带参数的宏替代实际的函数有两个优点:程序可能会稍微快些。一个函数调用在执行时通常会有些额外开销程序可能
18、会稍微快些。一个函数调用在执行时通常会有些额外开销存储上下文信息、复制参数的值等。而一个宏的调用则没有这存储上下文信息、复制参数的值等。而一个宏的调用则没有这些运行开销。些运行开销。宏会更宏会更“通用通用”。与函数的参数不同,宏的参数没有类型。只要预。与函数的参数不同,宏的参数没有类型。只要预处理后的程序依然是合法的,宏可以接受任何类型的参数。处理后的程序依然是合法的,宏可以接受任何类型的参数。v带参数的宏也有一些缺点。带参数的宏也有一些缺点。编译后的代码通常会变大。每一处宏调用都会导致插入宏的替换列编译后的代码通常会变大。每一处宏调用都会导致插入宏的替换列表,由此导致程序的源代码增加表,由此
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 预处理器 预处理 PPT 课件
限制150内