第9章编译预处理
第9章 编译预处理
*1、宏定义 ■*2、文件包含 3、条件编译
◼ *1、宏定义 ◼ *2、文件包含 ◼ 3、条件编译
预处理命令 编译预处理:在编译源程序之前根据预处理命 令对源程序进行的预加工,由编译系统中的预 处理程序完成。 ■格式:以符号“#”开头 如:# include< math. h ■位置:宏定义与文件包含命令一般放在程序的 开头(原则上可以放在程序中的任意位置) 作用域:从定义起直到其所在源程序的末尾 使用预处理命令的好处:(分别介绍) 改进程序设计环境,提高编程效率,易读、易改
预处理命令 ◼ 编译预处理:在编译源程序之前根据预处理命 令对源程序进行的预加工,由编译系统中的预 处理程序完成。 ◼ 格式:以符号 “ # ” 开头 ◼ 如:#include ◼ 位置:宏定义与文件包含命令一般放在程序的 开头(原则上可以放在程序中的任意位置) ◼ 作用域:从定义起直到其所在源程序的末尾。 ◼ 使用预处理命令的好处: (分别介绍) 改进程序设计环境,提高编程效率,易读、易改
91宏定义 不带参数的宏定义: 常用于将一些有特殊含义的常量定义成符号常量,使程 序易读、易改。 例如3.14代表,271代表e,用-1表示文件的结束标 志等。如果在程序中直接用3.14,2.71,-1等这些值,会 出现以下问题 )数值的含义不明显,影响程序的可读性 2)若程序中多次使用某一个常量,要修改时必须 修改,即麻烦又易出错。 用不带参数的宏定义,可以很好的解决此问题
9.1 宏定义 一、不带参数的宏定义: 常用于将一些有特殊含义的常量定义成符号常量,使程 序易读、易改。 例如3.14代表 ,2.71代表e,用-1表示文件的结束标 志等。如果在程序中直接用3.14,2.71,-1等这些值,会 出现以下问题: 1) 数值的含义不明显,影响程序的可读性。 2)若程序中多次使用某一个常量,要修改时必须一一 修改,即麻烦又易出错。 用不带参数的宏定义,可以很好的解决此问题。
不带参数的宏定义 如符号常量的定义: #define pi 3. 14 #define e 2.71 #define eof -1 #define null 0 #define NUM stu 30 若程序中有语句: for(j-o j<NUM STU: j++) sum+-scoreLjl 则编译预处理时,语句中的 NUM STU用30来代替: for(=0; j<30: j++) sum+-scoreljl
不带参数的宏定义 如符号常量的定义: #define PI 3.14 #define E 2.71 #define EOF -1 #define NULL 0 #define NUM_STU 30 若程序中有语句: for(j=o;j<NUM_STU;j++) sum+=score[j]; 则编译预处理时,语句中的NUM_STU用30来代替: for(j=0;j<30;j++) sum+=score[j];
不带参宏定义的一般形式: # define宏名宏体 宏名一般用大写,以区别于其他变量 宏体是字符串,可以是常数、常量表达式或语句。 作用:预处理时,进行宏替换,即用宏体代替宏名。 注意 1)一行只能写一个宏定义语句 2)宏名的起名规则同标识符的起名规则。 3)宏定义命令不是语句,末尾不需加分号(;) 例求圆的周长、面积中用3.14代替PI.(略)
不带参宏定义的一般形式: #define 宏名 宏体 宏名一般用大写,以区别于其他变量; 宏体是字符串,可以是常数、常量表达式或语句。 作用:预处理时,进行宏替换,即用宏体代替宏名。 注意: 1)一行只能写一个宏定义语句 2) 宏名的起名规则同标识符的起名规则。 3) 宏定义命令不是语句,末尾不需加分号(;) 例求圆的周长、面积中用3.14代替PI.(略)
宏定义的嵌套: #define one 1 #define TWo (OnEone #define THREE(TWo+one) 若原程序中有如下语句: printf(9d,%d,%d”,ONE,TWO, THREE);则预处理后为: printf(“%d,%d,%d”,1,(1+1),(1+1)+1); 结论:宏替换只是简单的用宏体字符串代替宏名,并不进行计算。 因为计算是在执行程序时进行的,而宏替换是编译之前进行的。 特别提示:宏体一般用括号括起来,避免宏替换后改变原来的运 算顺序 如:# define n10 define m n+4 语句:M*5替换后为:10+4*5(与原运算顺序不符)
宏定义的嵌套: #define ONE 1 #define TWO (ONE+ONE) #define THREE (TWO+ONE) 若原程序中有如下语句: printf(“%d,%d,%d”,ONE,TWO,THREE); 则预处理后为: printf(“%d,%d,%d”,1,(1+1),((1+1)+1)); 结论:宏替换只是简单的用宏体字符串代替宏名,并不进行计算。 因为计算是在执行程序时进行的,而宏替换是编译之前进行的。 特别提示:宏体一般用括号括起来,避免宏替换后改变原来的运 算顺序。 如:#define N 10 #define M N+4 语句:M*5 替换后为: 10+4*5 (与原运算顺序不符)
带参宏定义 常用于实现简单的操作,与函数功能类似 例92求三树种的最大值。其中,求两数中的较大数 用宏定义实现。 #define maX(a, b) (a>b)?(a):(b) main intx=10,y=20,z30; int t t=MAX(x,y);/预处理后:t=(x>y)?(x):(y);* printf(n %od, MAX(t, 2); /预处理后:prin(n%d”(t>n)?(t):(z);*
二、带参宏定义 ◼ 常用于实现简单的操作,与函数功能类似。 ◼ 例9.2 求三树种的最大值。其中,求两数中的较大数 用宏定义实现。 #define MAX(a,b) (a>b)?(a): (b) main() {int x=10, y=20, z=30; int t; t=MAX(x , y); /*预处理后: t=(x>y)?(x): (y); */ printf(“\n%d”,MAX(t , z)); /*预处理后: printf(“\n%d”,(t>z)?(t): (z)); */ }
带参宏定义的一般形式: # define宏名(参数表)宏体 预处理时进行如下宏替换 用宏体替换宏名的同时,用实参分别替换形参, 而不是用实参的值,即替换时不进行任何计算。 本例中的语句:t=MAX(x,y); 若理解为:t=(10>20)(10):(20);则错
带参宏定义的一般形式: #define 宏名(参数表) 宏体 预处理时进行如下宏替换: 用宏体替换宏名的同时,用实参分别替换形参, 而不是用实参的值,即替换时不进行任何计算。 本例中的语句: t=MAX(x , y); 若理解为:t=(10>20)?(10): (20); 则错
特别提示:使用带参宏定义时,宏体、宏体中的参数 用括号扩起来,以保证替换后不影响原来的运算顺序 例:# define SQ(a) aa 若有语句:y=SQ(mn; 则于处理后变成:y=m+nm+n 明显与原题意不符。 应定义为:# define sq(a)(a)*(a) 取消宏定义: 当程序中已不再需要某个宏定义,或需改变某个宏定义 可以用取消宏定义命令取消前面定义的宏。如 #define len 100 #undef LEN
◼ 特别提示:使用带参宏定义时,宏体、宏体中的参数要 用括号扩起来,以保证替换后不影响原来的运算顺序。 例: #define SQ(a) a*a 若有语句: y=SQ(m+n); 则于处理后变成: y=m+n*m+n; 明显与原题意不符。 应定义为:#define SQ(a) (a)*(a) 三、取消宏定义: 当程序中已不再需要某个宏定义,或需改变某个宏定义时, 可以用取消宏定义命令取消前面定义的宏。如: #define LEN 100 …… #undef LEN ……