第13章 编译预处理 宏定义 文件包含 条件编译
作用:在程序编译之前对程序做一些处理 种类 格式 宏定义 #define 文件包含 #include 条件编译 #if---#else---#end if 格式 以#开头 命令尾不加分号
§13.1 宏定义 一、不带参数的宏定义 一般形式:#define 标识符 字符串 作用:用指定的标识符(宏名)代替字符串 宏名通常用大写字母表示,以于变量名相区别 如 #define YES 1 #define NO 0 #define PI 3.1415926 #define OUT printf("hello!");
说明 宏名定义位置:任意(一般在函数的外部) 宏展开: 预编译时,用字符串替换宏名 ---不作语法检查 宏展开 #define YES 1 #define NO 0 main() { int x; if (x==YES) printf("good!"); else if (x==NO) printf("error!"); } #define YES 1 #define NO 0 main() { int x; if (x==1) printf("good!"); else if (x==0) printf("error!"); } 如错写成#define YES l 宏展开 宏展开if(x== l)
宏展开时,程序中用双撇号括起的字符串内的与宏名相同的字符,不进行置换 #define PI 3.1415926 main(){ printf("PI=%f",PI);} 宏展开后: printf("PI=%f",3.1415926); 宏名作用域:从定义位置开始到本文件结束 用#undef可终止宏名作用域 格式:#undef 宏名 #define YES 1 main() {…… } #undef YES #define YES 0 void max() {…… YES原作用域 YES新作用域
宏定义时可以引用已定义的宏名,层层置换 宏定义中注意括号的使用 宏展开 x=80+40*2; 宏展开 x=(80+40)*2; #define WIDTH 80 #define LENGTH WIDTH+40 main() {int x; x=LENGTH*2; } 宏展开 x=80+40*2; 宏定义中注意括号的使用 #define WIDTH 80 #define LENGTH (WIDTH+40) main() {int x; x=LENGTH*2; } 宏展开 x=(80+40)*2;
二、带参数的宏定义 一般形式:#define 宏名(参数表) 字符串 作用:不只是字符串替换,还包含参数替换 包含参数表中指定的参数 不能加空格 二、带参数的宏定义 一般形式:#define 宏名(参数表) 字符串 作用:不只是字符串替换,还包含参数替换 宏展开:形参用实参换,其它字符不变 #define S (a,b) a*b 相当于定义了无参宏名S,代表字符串"(a,b) a*b" #define S(a,b) a*b main() {float area; area=S(3,2); } 宏展开 area=3*2;
宏体及形参一般应用括号括上 #define MAX(x,y) (x)*(y) #define MAX(x,y) x*y main() {int a,b,c,d,t; …… t=MAX(a+b,c+d); } #define MAX(x,y) x*y main() {int a=3,b=4,c=5,d=6,t; …… t=MAX(a+b,c+d); } 改写成 不同于函数调用 宏展开 宏展开 t=a+b*c+d; t=(a+b)*(c+d);
<例> #define POWER(x) x*x x=4; y=6; z=POWER(x+y); 宏展开:z=x+y*x+y; 一般写成: #define POWER(x) ((x)*(x)) 宏展开: z=((x+y)*(x+y)); <练>以下程序执行的输出结果是( )。 #define MIN(x,y) (x)<(y)?(x):(y) main() { int i,j,k; i=10;j=15; k=10*MIN(i,j); printf("%d\n",k); } A.15 B.100 C.10 D.150
#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); { int a,b,c,d,t; t=max(a+b,c+d); ……… <例> 用宏定义和函数实现同样的功能
带参的宏与函数区别 带参宏 函数 处理过程 不分配内存 简单的字符置换 分配内存 先求实参值,再代入形参 处理时间 编译时 程序运行时 参数类型 无类型问题 定义实参,形参类型 程序长度 变长 不变 运行速度 不占运行时间 调用和返回占时间
§13.2 “文件包含”处理 功能:一个源文件可以将另一个源文件的内容全部包含进来(可以减少重复劳动) 一般形式:#include "文件名" 或:#include <文件名> 说明: 两种形式的区别: 使用双撇号"": 使用尖括号<>: 系统先在当前目录下查找,在到系统指定的包含文件目录查找 直接到系统指定的包含文件目录查找
处理过程: 预编译时,用被包含文件的内容取代该预处理命令,再对整个文件编译 B B #include "file2.c" file2.c A 在被包含文件中的全局变量在包含文件中也是有效的,不用声明 A file1.c B B file2.c #include "file2.c" A file1.c
被包含文件类型: 源文件(*.c) 头文件(*.h) 文件包含可以嵌套 #include"file3.c" file2.c B C A file1.c
/* powers.h */ #define sqr(x) ((x)*(x)) #define cube(x) ((x)*(x)*(x)) #define quad(x) ((x)*(x)*(x)*(x)) /*ch8_10.c*/ #include <stdio.h> #include "d:\fengyi\bkc\powers.h" #define MAX_POWER 10 void main() { int n; printf("number\t exp2\t exp3\t exp4\n"); printf("----\t----\t-----\t------\n"); for(n=1;n<=MAX_POWER;n++) printf("%2d\t %3d\t %4d\t %5d\n",n,sqr(n),cube(n),quad(n)); } <例> 文件包含举例
§9.3 条件编译 条件编译:对文件的一部分内容只有在满足一定的条件才进行编译 形式: #ifndef 标识符 #if 表达式 程序段1 形式1: 形式2 形式3 #ifdef 标识符 程序段1 #else 程序段2 #endif #ifndef 标识符 程序段1 #else 程序段2 #endif #if 表达式 程序段1 #else 程序段2 #endif 说明1:若标识符被定义过,则编译程序段1,否则编译程序段2,这种形式正好与形式2相反。 说明2:当指定的表达式值为真就编译程序段1,否则编译程序段2
例:输入一行字母,根据需要设置条件编译,使之能将字母全改为大写或全改为小写。 #define LETTER 1 main() { char str[20]=“CLanguage”,c; int i; i=0; while((c=str[i]!=‘\0’) {i++; #if LETTER if(c>=‘a’&&c<=‘z’) c=c-32; #else if(c>’A’&&c<=‘Z’) c=c+32 #endif printf(“%c”,c); } 条件 编译