c语言编译预处理.ppt
第八章本章主要内容本章主要内容1.掌握无参宏定义和带参宏定义的方法掌握无参宏定义和带参宏定义的方法2.掌握文件包含命令的形式和文件包含的掌握文件包含命令的形式和文件包含的实现过程实现过程3.了解条件编译命令了解条件编译命令 C的源程序的源程序 预处理预处理 编译编译 目标程序目标程序 (*.C)_ (*.OBJ)编译系统中有编译系统中有 :预处理程序预处理程序 编译程序编译程序宏替换#define N 20 文件包含#include条件编译 if(.)C中的预处理命令中的预处理命令分类分类宏定义有两种类型宏定义有两种类型:字符串替换和带参数的宏替换字符串替换和带参数的宏替换 1 字符串宏替换字符串宏替换 功能:功能:在预处理时在预处理时,将程序中宏定义之后出现的将程序中宏定义之后出现的所有的宏名所有的宏名,用宏替换体代替。用宏替换体代替。宏替换名宏替换名宏替换体宏替换体例如:例如:#define PI 3.14159 格式:格式:#define 标识符字符串标识符字符串 C的编译程序调用预处理程序检查有否的编译程序调用预处理程序检查有否宏名宏名,若,若有,用有,用宏替换体宏替换体将其替换,完成之后,将替换后的源将其替换,完成之后,将替换后的源程序交该编译程序。程序交该编译程序。8.1 8.1 宏定义宏定义 用途用途:常用的符号常数常用的符号常数 PI=3.14159 自然对数的底自然对数的底:2.71828 数组的长度数组的长度#define N 10 /*编译之前用编译之前用10替换所有的替换所有的N */.int aN 说明说明:v 通常放在程序开头通常放在程序开头,不加分号不加分号v 是代替是代替,不是赋值不是赋值(不作语法检查不作语法检查)v 可将多个语句或表达式定义为一个宏替换可将多个语句或表达式定义为一个宏替换v 区别变量和关键字区别变量和关键字,习惯用大写习惯用大写#define R 3.0#define PI 3.145926#define L 2.0*PI*R#define S PI*R*Rv 双引号中的不替换双引号中的不替换v 有效范围有效范围,从定义开始到程序结尾从定义开始到程序结尾例:例:#define PI 3.14159main()printf(“PI=%fn”,PI);结果:结果:PI=3.14159main()printf(“PI=%fn”,”PI”);v 可以嵌套可以嵌套,后定义的宏可以包含先定义的宏名后定义的宏可以包含先定义的宏名结果结果:PI=PI2 带参数的宏定义带参数的宏定义 带参数的宏不仅能进行字符串代替,而且还进带参数的宏不仅能进行字符串代替,而且还进行参数代换。行参数代换。格式:格式:#define 宏名(参数表)宏名(参数表)表达式表达式 功能功能:带参数的宏将一个带参数的宏将一个带形参带形参的表达式定义为一个带参数的表达式定义为一个带参数的宏名,预处理程序对程序中所有的宏名,预处理程序对程序中所有带实参带实参表的宏名进行表的宏名进行宏宏展开展开替换,替换,用表达式代替宏名,用参数表中的实参代替表用表达式代替宏名,用参数表中的实参代替表达式中对应达式中对应 的形参的形参。例:例:#define S(a,b)a*b程序中程序中 S(3,2)3*2 用途:用途:用带参数的宏可以代表一些简短的表达式,提高用带参数的宏可以代表一些简短的表达式,提高程序执行的效率。程序执行的效率。*宏定义可以嵌套宏定义可以嵌套*对常用的格式输入输出函数对常用的格式输入输出函数printfprintf可以进行宏定可以进行宏定义,使程序简化义,使程序简化*宏名与参数的圆括号之间不能有空格宏名与参数的圆括号之间不能有空格 s (a,b)s (a,b)说明:说明:*宏定义命令要求在一行内写完,如换行,用宏定义命令要求在一行内写完,如换行,用“”表示下一行继续。表示下一行继续。*对于宏定义的形参要根据需要加上圆括号,以免对于宏定义的形参要根据需要加上圆括号,以免 发生运算错误发生运算错误例例1 使用有参宏替换求园的面积。使用有参宏替换求园的面积。#define PI 3.1415926#define S(r)PI*r*r main()float a=3.6,area;area=S(a);printf(“r=%fnarea=%fn”,a,area);例例2 求下列语句的循环次数。求下列语句的循环次数。#include“stdio.h”#define N 2#define M N+1#define NUM(M+1)*M/2 main()int i,n=0;for(i=1;i=NUM;i+)n+;printf(“%d”,n);例例3 用两种方法计算用两种方法计算1-10的平方(函数,宏)的平方(函数,宏)square(n)int n;return(n*n);main()int i=1;while(i=10)printf(“%dn”,square(i+);用函数方法:用函数方法:用带参数的宏方法:用带参数的宏方法:#define SQUARE(n)(n*n)main()int i=1;while(i=10)printf(“%dn”,SQUARE(i+);(i+)*(i+)实参的求值顺序是实参的求值顺序是:从右向左从右向左第一次循环第一次循环:i=1 2*1 之后之后 i为为3第二次循环第二次循环:i=3 4*3 之后之后 i为为5第三次循环第三次循环:i=5 6*5 之后之后 i为为7 第四次循环第四次循环:i=7 8*7 之后之后 i为为9.1到到22到到3函数要求形参,实参有类型(相同)函数要求形参,实参有类型(相同)宏的形参,实参不要求类型,仅是符号宏的形参,实参不要求类型,仅是符号函数需事先计算实参表达式的值,再代入形参函数需事先计算实参表达式的值,再代入形参宏展开中不求表达式的值,仅替换宏展开中不求表达式的值,仅替换,没有值传递没有值传递函数是在运行时处理函数是在运行时处理宏是在编译之前进行宏是在编译之前进行带参数的宏与函数的区别带参数的宏与函数的区别函数调用影响运行时间,源程序无变化函数调用影响运行时间,源程序无变化宏展开影响编译时间,通常使源程序加长宏展开影响编译时间,通常使源程序加长函数调用有一个返回值函数调用有一个返回值 宏可以有多个结果宏可以有多个结果例例:求最大值。求最大值。(答案中用答案中用U代表空格代表空格)#include#define _A_main()float a,b,c,d;scanf(%f%f,_B_ );c=MAX(a,b);d=MAX(3+a,4*b);printf(c=%f,d=%f.n,c,d);A:MAX(x,y)Uxy?x:yB:&a,&b 文件包含是指一个程序文件将另一个指定文件的文件包含是指一个程序文件将另一个指定文件的全部内容包含进来。全部内容包含进来。格式格式:#include 或或:#include “文件名文件名”8.2 8.2 文件包含文件包含 功能功能:用指定文件的全部内容代换该预处理行用指定文件的全部内容代换该预处理行,C程序通过程序通过#include预处理预处理,把一个指定的文件的把一个指定的文件的内容嵌入。内容嵌入。只能包含只能包含ASCII文本文件。文本文件。与与“”的区别的区别:在在TCTC标准目录下找指定文件标准目录下找指定文件 “”在用户当前目录下找指定文件在用户当前目录下找指定文件,如用户当前目如用户当前目录下没有录下没有,再到再到TCTC标准目录下找。标准目录下找。说明说明 只包含源文件只包含源文件,不包含可执行文件和目标文件。不包含可执行文件和目标文件。可以嵌套可以嵌套例如例如:file1.cfile1.c需包含需包含file2.c,file2.c,file2.cfile2.c包含包含file3.cfile3.c,在,在file1file1中中,用两次用两次#include#include#include,#include,必须将必须将file3.hfile3.h放在前面放在前面 一个一个#include#include只能包含一个文件只能包含一个文件用途用途 将符号常量将符号常量,带参数的宏及构造类型的变量等带参数的宏及构造类型的变量等定义在一个独立的文件中定义在一个独立的文件中,为其他文件共享。为其他文件共享。程序员可将工作中积累的有价值的符号程序员可将工作中积累的有价值的符号,带参数带参数的宏定义的宏定义,或一些外部变量或一些外部变量,通用的子程序定义成一通用的子程序定义成一个文件个文件,需要时需要时,包含进源程序。包含进源程序。使用使用C中的库函数中的库函数,需将所在的头文件包含进源需将所在的头文件包含进源程序。程序。“文件包含文件包含”示意图示意图 file1.c file2.c file1.c 包含包含#include”file2.c”B A B A (a)(b)(c)8.38.3条件编译条件编译8.3.1条件编译命令的形式条件编译命令的形式 常用的有三种形式:常用的有三种形式:形式一:形式一:#ifdef 宏名宏名 程序段程序段1;#else 程序段程序段2;#endif 或者:或者:#ifdef 宏名宏名 程序段;程序段;#endif 形式二:形式二:#ifndef 宏名宏名 程序段程序段1;#else 程序段程序段2;#endif其中,其中,#ifndef语句的功能与语句的功能与#ifdef相反,如果宏名相反,如果宏名未定义则编译程序段未定义则编译程序段1,否则编译程序,否则编译程序2。或者:或者:#ifndef 宏名宏名 程序段;程序段;#endif形式三:形式三:#if 常数表达式常数表达式 程序段程序段1;#else 程序段程序段2;#endif 功功能能:首首先先计计算算“常常数数表表达达式式”的的值值,如如果果为为真真(非非零零),就就编编译译“程程序序段段1”,否否则则编编译译“程程序序段段2”。如如果果没没有有#else部部分分,则则当当“常常数数表表达达式式”的值为的值为0时,直接跳过时,直接跳过#endif。或者:或者:#if 常数表达式常数表达式 程序段;程序段;#endif例:阅读程序。例:阅读程序。#include main()#if NULL printf(NULL is non-zero value!n);#else printf(NULL is zero value!n);#endif运行结果:运行结果:NULL is zero value!8.3.2条件编译命令的嵌套条件编译可以嵌套使用,如:条件编译可以嵌套使用,如:#if表达式表达式1程序段程序段1;#else#if 表达式表达式2 程序段程序段2;#else 程序段程序段3;#endif#endif