第十五讲 宏定义
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第十五讲宏定义、文件包含和条件编译
❑C语言提供的预处理功能主要有三种:
宏定义
文件包含
条件编译
❑为了区别预处理命令和C语句、定义和说明语句,规定:
预处理命令行必须在一行的开头;
必须以#开始;
每行末尾不能加分号。
1、宏定义
宏定义
1.1不带参数的宏定义
不带参数的宏定义命令形式为:
#define 宏名字符串
或#define 宏名
#define的作用是用指定的标识符(宏名)来代表字符串。其中#define是宏定义命令,宏名是一个标识符。
【例】输入一个圆的半径,计算并输出圆的面积和周长
#define PI 3.14159
main( )
{float l,s,r; /*l:周长,s:面积,r:半径*/
printf("Please input radius: ");
scanf("%f",&r); /*输入半径*/
l=2.0*r*PI; /*计算周长*/
s=PI*r*r; /*计算面积*/
printf("l=%10.4f\ns=%10.4f\n",l,s);
}
说明:
为了与变量名区别,建议宏名一般用大写字母。使用宏名代替一个
字符串,目的一是减少程序中某些重复使用字符串的书写量,其二
是增加程序的可读性。在编译预处理过程中会进行宏展开。
当宏定义在一行中写不下,需要在下一行继续时,只需在最后一个
字符后紧接一个反斜线“\”。注意在第二行开始不要有空格,否则空
格会一起被替换。
例如:#define LEAP_YEAR year % 4==0\
&& year %100!=0 || year % 400==0
在C语言中,宏定义一般写在程序开头。宏名的有效范围为定义命
令之后到本源文件结束,除非用#undef命令终止宏名的作用域。
对程序中用双引号括起来的字符串内的子串和用户标识符中的成分
不做替换。例如已定义:
同一个宏名不能重复定义,除非两个宏定义命令行完全一致。
1.2带参数的宏定义
形参表中的不同形参之间用逗号隔开,字符串中包含形参表中的参数,带参
数的宏定义命令形式为:
#define 宏名(形参表)字符串
【例6.2】分析下面程序的执行结果
#define M(x,y) (x*y)
main( )
{int a=2,b=3,c=4,d=5;
int x=M(a+b,c+d);
printf("%d",x);
}
程序运行结果为:19。宏替换结果为2+3*4+5。
说明:
在调用带参数的宏名时,注意实参和形参一定要一一对应,个数相
同,顺序一致。
和不带参数的宏定义相同,同一个宏名不能重复定义,除非两个宏
定义完全相同。
带参数的宏定义时,注意字符串中的括号的使用。比较下列两个宏
定义在替换后的不同:
其一其二
宏定义:#define MU(x,y) x*y #define MU(x,y) (x)*(y)
宏调用:6/MU(2+3,4+5) 6/MU(2+3,4+5)
结果:6/2+3*4+5即3+3+4+5=15 6/(2+3)*(4+5)即6/5+9
其三其四
宏定义:#define MU(x,y) (x*y) #define MU(x,y) ((x)*(y))
宏调用:6/MU(2+3,4+5) 6/MU(2+3,4+5)
结果:6/(2+3*4+5)即6/19 6/((2+3)*(4+5))即6/45
在宏调用中,实参不能替换括在双引号中的形参。
在进行宏定义时,可以引用已经定义过的宏名。
#define R 3.0
#define PI 3.14159
#define L 2.0*PI*R /*使用了已定义的宏名PI和R*/
#define S PI*R*R /*使用了已定义的宏名PI和R*/
【例】
#define PR(a) printf("%d\t",a)
#define PRINT(a) PR(a);printf("ok!") /*使用已定义的宏名PR(a)*/
main( )
{int i,a=1;
for(i=0;i<3;i++)
PRINT(a+i);
printf("\n");
}
终止宏定义
宏命令#undef用于终止宏定义的作用域。一般形式为:
#undef 宏名
例如:
#defin MU(x,y) ((x)*(y))
main( )
{ …
}
#undef MU(x,y)
function1( )
{ …
}
#undef 也可以用于一个函数的内部。
#define PI 3.14159
main( )
{ …
#undef PI
…
}
❑宏调用和函数调用的主要不同:
函数调用时,先求出实参的值,用实参的值代入形参;带参数的宏调用时,用实参的字符串代替形参,只是一种简单的字符替换。
函数调用在程序运行时完成,函数调用的过程由程序代码完成,分配临时的内存单元,占用运行时间;宏展开是在编译时由编译预处理程序完成的,仅
仅是一种简单的替换,因此宏调用不占有运行时间。
函数调用中要求实参和形参的类型一致;宏不存在类型问题,宏名无类型,它的参数也没有类型,只是一个符号代表。
函数调用一般会得到函数值。
2、文件包含
❑文件包含是指将另外一个源文件的内容包含到当前文件中来。
❑C语言提供了文件包含命令#include实现文件包含。#include命令的格式为:
#include “文件名” 或
#include <文件名>
❑说明:
一个include命令只能指定一个被包含文件,如果需要包含n个文件,可以用n个include命令。
#include命令应书写在所用文件的开头,故有时也把包含文件称作“头文件”。
头文件常用“h”作为后缀,当然也可以用其它后缀或没有后缀。
如果文件f1包含文件f2,f2又包含文件f3,这种情况叫做包含嵌套。包含嵌套的处理方式有两种,
C语言本身也为用户提供了许多库子程序,包括标准函数和宏定义。用户可以在自己的程序中使用这些库子程序完成一系列工作。与函数相关的信息存在
一些后缀为.h的头文件中。用户要想使用这些库函数,必须用#include命令
将有关头文件包含在自己的源程序中。
【例】
#include
#include
main( )