1 / 18

第 九 章 预 处 理 命 令

第 九 章 预 处 理 命 令. 主要内容. 一、什么是预处理 二、宏定义 三、 “ 文件包含 ” 处理 四、条件编译(不讲). 所谓预处理是指,在对源程序进行编译之前,先对源程序中的预处理命令( 主要指宏定义命令、文件包含命令和条件编译命令 )进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。. 编译预处理. 编译. 连接. 执行. 一、什么是预处理. # define # include. 宏定义 文件包含 条件编译. (一)不带参数的宏定义 (二)带参数宏定义. 二、宏定义. (一)不带参数的宏定义(简单替换).

junius
Download Presentation

第 九 章 预 处 理 命 令

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第 九 章预 处 理 命 令

  2. 主要内容 一、什么是预处理 二、宏定义 三、“文件包含”处理 四、条件编译(不讲)

  3. 所谓预处理是指,在对源程序进行编译之前,先对源程序中的预处理命令(主要指宏定义命令、文件包含命令和条件编译命令)进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。所谓预处理是指,在对源程序进行编译之前,先对源程序中的预处理命令(主要指宏定义命令、文件包含命令和条件编译命令)进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。 编译预处理 编译 连接 执行 一、什么是预处理 #define #include 宏定义 文件包含 条件编译

  4. (一)不带参数的宏定义 (二)带参数宏定义 二、宏定义

  5. (一)不带参数的宏定义(简单替换) 用标识符来代表一个字符串(给字符串取个名字)。C语言用“#define”进行宏定义。C编译系统在编译前将这些标识符替换成所定义的字符串。 概念 格式 #define 标识符 字符串 #define PI 3.1415926 相关概念 宏名: 宏定义中的标识符称为“宏名”。 宏调用:在程序中用宏名替代字符串称为“宏调用”。 宏展开:在预编译时将宏名替换成字符串的过程称 为“宏展开”。

  6. 输入圆的半径,求圆的周长、面积和球的体积。要求使用无参宏定义圆周率。输入圆的半径,求圆的周长、面积和球的体积。要求使用无参宏定义圆周率。 例 1 #include <stdio.h> #define PI 3.1415926 /*宏定义PI是宏名,用来替换常数3.1415926 */ void main() { float radius,length,area,volume; printf("Input a radius: "); scanf("%f",&radius); length=2*PI*radius; /*宏调用,引用无参宏求周长*/ area=PI*radius*radius; /*宏调用,引用无参宏求面积*/ volume=PI*radius*radius*radius*3/4; /*宏调用,引用无参宏求体积*/ printf("length=%.2f,area=%.2f,volume=%.2f\n", length, area, volume); } 宏展开: length=2*3.1415926*radius; area= 3.1415926*radius*radius; volume= 3.1415926*radius*radius*radius*3/4;

  7. 1、宏名遵循标识符规定,习惯用大写字母表示,以便区别普通的变量。 2、#define之间不留空格,宏名两侧空格(至少一个)分隔。 3、宏定义字符串不要以分号结束,否则分号也作为字符串的一部分参加展开。从这点上看宏展开实际上是简单的替换。 宏展开 说明 #define PI 3.14; area=PI*r*r; area=3.14;*r*r;

  8. 4、宏定义是预处理指令,与定义变量不同,它只是进行简单的字符串替换,不分配内存。4、宏定义是预处理指令,与定义变量不同,它只是进行简单的字符串替换,不分配内存。 5、宏定义用宏名代替一个字符串,并不管它的数据类型是什么,也不管宏展开后的词法和语法的正确性,只是简单的替换。是否正确,编译时由编译器判断。 例如: #define PI 3.I4 照样进行宏展开(替换),是否正确,由编译器来判断。 说明

  9. 6、#define命令出现在程序中函数的外面,宏名的有效范围从定义命令开始直到本源程序文件结束。可以通过#undef终止宏名的作用域。6、#define命令出现在程序中函数的外面,宏名的有效范围从定义命令开始直到本源程序文件结束。可以通过#undef终止宏名的作用域。 G的有效范围 PI的有效范围 说明 #define G 9.8 #define PI 3.14 int f1() { … … } #undef G void main() { … … }

  10. 7、宏定义时,可以引用已定义的宏名,可以层层置换。若宏名出现在双引号“”括起来的字符串中时,将不会产生宏替换。7、宏定义时,可以引用已定义的宏名,可以层层置换。若宏名出现在双引号“”括起来的字符串中时,将不会产生宏替换。 宏展开 说明 #define R 3.0 #define PI 3.14 #define L 2*PI*R #define S PI*R*R void main() { printf(“L=%f\nS=%f\n”,L,S); } printf(“L=%f\nS=%f\n”,2*3.14*3.0 , 3.14*3.0*3.0);

  11. 宏展开 (二)带参数的宏定义 带参数的宏定义不只是进行简单的字符串替换,还要进行参数替换。 概念 类似函数头,但是没有类型说明,参数也不要类型说明 格式 #define 宏名(参数表) 字符串 按照#define命令行中指定的“字符串”从左到右进行置换(扫描置换)。如果串中包含宏定义中的形参,则将程序中相应的实参代替形参,其它字符原样保留,形成了替换后的字符串。 展开置换规则 #define S(a,b) a*b area=S(3,2); 举例 area=3*2;

  12. 宏展开 area=3.14*a*a; 例 2 用带参数的宏定义表示圆的面积。 #define PI 3.14 #define S(r) PI*r*r void main() { float a,area; a=3.6; area=S(a); printf(“r=%f\narea=%f\n”,a,area); }

  13. 1、正因为带参宏定义本质还是简单字符替换(除了参数替换),所以容易发生错误。1、正因为带参宏定义本质还是简单字符替换(除了参数替换),所以容易发生错误。 例:#define S(r) 3.14*r*r area=S(a+b); 宏展开 说明 不再是求面积了。 area=3.14*a+b*a+b; 2、定义带参数宏时还应该注意宏名与参数表之间不能有空格。有空格就变成了不带参数的宏定义。 例:#define S(r) 3.14*r*r 此时S是符号常量(不带参的宏名),它代表字符串“(r) 3.14*r*r”。

  14. 说明 3、带参数的宏定义与函数的本质区别 1)函数调用时,先求表达式的值,然后将值传递给形参;带参宏展开只在编译时进行的简单字符置换。 2)函数调用是在程序运行时处理的,给形参分配临时的内存单元;而宏展开是在编译时进行的,展开时并不给形参分配内存,也不进行“值传递”,也没有“返回值”的概念。 3)函数的形参要定义类型,且要求形参、实参类型一致。宏不存在参数类型问题。 4)宏占用的是编译时间,函数调用占用的是运行时间。在多次调用时,宏使得程序变长,而函数调用不明显。

  15. 1、程序中的常量可以用有意义的符号代替,程序更加清晰,容易理解(易读)。1、程序中的常量可以用有意义的符号代替,程序更加清晰,容易理解(易读)。 2、常量值改变时,不用在整个程序中查找修改,只要改变宏定义就可以。比如,提高PI精度值。 3、带参数宏定义比函数调用具有更高的时间效率,因为相当于代码的直接嵌入。(空间效率:多次调用占用空间较多,一次调用没有什么影响)。 总结:使用宏的优点

  16. file1.c file1.c file2.c 包含 #include <file2.c> B B A A 三、“文件包含”处理 所谓“文件包含”处理是指一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。 概念 #include “文件名”或 #include <文件名> 格式 示意图

  17. 1、被包含的文件常常被称为“头文件”(#include一般写在文件的开头)。头文件常常以“.h”为扩展名(也可以用其它的扩展名,.h只是习惯或风格)。 2、一条#include只能包含一个头文件,如果要包含多个头文件,使用多条#include命令。 3、在一个被包含的文件中又可以包含另一个被包含文件,即文件包含是可以嵌套的。 4、被包含的头文件可以用“”括起来,也可以用<>括起来。区别在于: “”先在用户当前目录查找头文件,如果没找到,再到存放C库函数头文件的目录中查找;而<>直接到存放C库函数头文件的目录中查找。 一般地说,使用双引号比较保险。 5、习惯上,用户头文件一般在用户目录下,所以常常用“”;系统库函数的头文件一般在系统指定目录下,所以常常用<>。 说明

  18. 作 业 P199: 9.1, 9.3, 9.5, 9.7

More Related