第九章 预处理命令
预处理命令概述
9.1 宏定义
9.2,文件包含”处理预处理命令概述
1,概念编译预处理是在编译前对源程序进行的一些预加工预处理由编译系统中的预处理程序,按源程序中的预处理命令进行
2,预处理命令
C语言的预处理命令均以,#,打头,末尾不加分号预处理命令可以出现在程序的任何位置,
其作用域是从出现点到所在源程序的末尾
3,优点,能改善程序设计的环境,
有助于编写易移植,易调试的程序
9.1 宏定义一,不带参数的宏定义
1,格式,#define 标识符 字符串
2,说明,
(1) 标识符也称 宏名,一般 用大写字母表示
(2) 预处理时将程序中所有的宏名用宏体替换,该过程称
,宏展开,; 但在程序中用,,括起来的字符串中,即使有的字符串与宏名相同,也不进行替换
#define SIZE 20
void main ( )
{ int x ;
x = SIZE+15 ;
printf(,SIZE=%d \n”,x ) ;
}
称为宏体输出结果,SIZE=35
称为宏名
(3) 宏定义只是一种简单的字符替代,不进行语法检查若将 #define SIZE 20 的 零 写成英文字母 ‘ o’,
程序中的 x = SIZE+15 ; 会替换为 x = 2o+15;
这时才会发现错误
(4) 宏定义不是 C语句,行末不加分号,
每条宏命令要单独占一行
(5) #define命令出现在函数的外部,宏名的有效范围为定义命令之后到本文件结束
(6) 可以用 #undef 命令终止宏定义的作用域
(7) 宏定义可以嵌套使用例 #define L 10
#define W 20
#define S L*W
(8) 宏定义与变量定义不同,它只作字符替换,
不分配内存空间
3,使用宏替换的优点,提高程序的可读性,易于修改二,带参数的宏定义
1,格式,#define 宏名 ( 形参表 ) 字符串
2,说明
(1) 宏定义时宏名与括号之间没有空格,
若有空格则会把空格后的所有字符都看成是宏体
(2) 带参数的宏在替换时,不仅宏名被宏体替换,
同时形参被实参替换
(3) 建议带运算符的宏体和形参要用 ( ) 括起来例 #define PI 3.14159
#define S(r) PI*r*r
void main ( )
{ float a,area ;
a = 3.6 ;
area = S(a);
printf(,%f \n”,area) ;
}
宏替换,
area = 3.14159*a*a ;
void main ( )
{ float a,b,area ;
a = 3.6 ;
b = 1.2 ;
area = S(a+b);
printf(,%f \n”,area) ;
}
#define PI 3.14159
#define S(r) PI* r * r
不带括号的宏替换,
area = 3.14159*a+b*a+b ;
带括号的宏替换,
area = 3.14159*(a+b)*(a+b) ;
*( )*(r)
① #define SQUARE(x) x*x
② #define SQUARE(x) (x)*(x)
③ #define SQUARE(x) ((x)*(x))
若 a=2.7/SQUARE(3.0)
宏展开
① a=2.7/3.0*3.0
② a=2.7/(3.0)*(3.0)
③ a=2.7/((3.0)*(3.0))
若 a=SQUARE(n+1)
宏展开
① a=n+1*n+1
② a=(n+1)*(n+1)
③ a=((n+1)*(n+1))
出错 出错
3,带参数的宏与函数的区别
(1) 函数调用 时,先求出实参表达式的值,再代入形参带参数的宏定义 只是进行简单的字符替换
(2) 函数调用 是在程序运行时处理,分配临时的内存单元宏展开 是在编译时进行的,在展开时不分配内存单元
(3) 对 函数 的形参和实参都要定义类型,且要求一致宏不存在类型问题,宏名无类型,其参数也无类型
(4) 调用函数只可得到一个返回值,
使用宏可以设法得到几个结果
(5) 函数调用 不会使源程序变长,宏展开 会使源程序增长
(6) 函数调用 占用运行时间,
宏展开 不占运行时间,只占编译时间
#define MAX(x,y) (x)>(y)?(x),(y)
main( )
( int a,b,c,d,t;
…….
t=MAX(a+b,c+d);
…….
}
宏替换,
t = (a+b)>(c+d)? (a+b):(c+d);
int max(int x,int y)
{return( x > y? x,y ) ;}
main( )
( int a,b,c,d,t;
…….
t=max(a+b,c+d);
…….
}
函数调用,
t = max(a+b,c+d);
#define PR printf
#define NL,\n”
#define D,%d”
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S,%s”
main()
{ int a,b,c,d;
char string[]=“CHINA”;
a=1; b=2; c=3; d=4;
PR(D1,a );
PR(D2,a,b);
PR(D3,a,b,c);
PR(D4,a,b,c,d);
PR(S,string );
}
宏展开,
printf (“%d””\n”,a );
printf (“%d”,%d”,a,b);
printf (“%d”,%d”,%d”,a,b,c);
printf (“%d”,%d”,%d”,%d”,a,b,c,d);
printf (“%s”,string);
运行结果:
1
1 2
1 2 3
1 2 3 4
CHINA
9.2,文件包含”处理一、文件包含的概念用 #include命令把另一个文件的整个内容嵌入进来二、文件包含的两种格式
1,格式 #include,文件标识”
文件标识可以包含有文件路径 (即文件在哪个目录下 )
使用时系统先在引用被包含文件的源文件所在的目录下寻找被包含文件,如果找不到,系统再按指定的标准方式检索其他目录,直到找到为止,
通常使用用户自己编写的文件时用,,
2,格式 #include <文件名 >
系统只按规定的标准方式检索文件目录通常使用系统提供的标准头文件时用 < >
3,说明
(1) 文件包含的作用 就是在编译预处理时将被包含文件的全部内容复制并插入到 #include命令处
(2) 一个 include命令只能指定一个被包含文件,如果有 n个被包含文件则需要用 n个 include命令,且 一个命令占一行
(3) 使用文件包含时,在被包含文件中绝对不能有 main函数
(4) 文件包含可以嵌套使用
(5) 被包含文件中的全局量在其所在的文件中有效例 文件 file1.cpp
#include <stdio.h>
#include,file2.c”
#include,file3.c”
void main ( )
{ int x,y,s1,s2 ;
scanf(“%d%d”,&x,&y) ;
s1 = max ( x,y ) ;
s2 = min ( x,y ) ;
printf(“max=%d\n”,s1) ;
printf(,min=%d\n”,s2) ;
}
文件 file2.c
int max (int a,int b)
{ return(a>b? a,b ) ; }
文件 file3.c
int min (int a,int b)
{ return(a<b? a,b ) ; }
文件 stdio.h的内容
int min (int a,int b)
{ return(a<b? a,b ) ; }
int max (int a,int b)
{ return(a>b? a,b ) ; }
void main ( )
{ int x,y,s1,s2 ;
scanf(“%d%d”,&x,&y ) ;
s1 = max ( x,y ) ;
s2 = min ( x,y ) ;
printf(“max=%d\n”,s1) ;
printf(,min=%d\n”,s2) ;
}
注,文件 file1.c,file2.c,file3.c都在目录 c:\tc\ 下文件 stdio.h的内容
int min (int a,int b)
{ return(a<b? a,b ) ; }
int max (int a,int b)
{ return(a>b? a,b ) ; }
例 文件 file1.c
#include <stdio.h>
#include,file3.c”
void main ( )
{ int x,y,s1,s2 ;
scanf(“%d%d”,&x,&y) ;
s1 = max ( x,y ) ;
s2 = min ( x,y ) ;
printf(“max=%d\n”,s1) ;
printf(,min=%d\n”,s2) ;
}
文件 file2.c
int max (int a,int b)
{ return(a>b? a,b ) ; }
文件 file3.c
#include,file2.c”
int min (int a,int b)
{ return(a<b? a,b ) ; }
void main ( )
{ int x,y,s1,s2 ;
scanf(“%d%d”,&x,&y ) ;
s1 = max ( x,y ) ;
s2 = min ( x,y ) ;
printf(“max=%d\n”,s1) ;
printf(,min=%d\n”,s2) ;
}