C语言程序设计 第九章 预处理命令
主要内容 9.1 宏定义 9.2 文件包含 9.3 条件编译
概述 在编译系统对C源程序编译之前,先由预处理程序对这些命令作处理,因而叫“预处理命令”。 前几章用到的#include和#define,就是预处理命令。预处理命令包括: 1. 宏定义 2. 文件包含 3. 条件编译
9.1 宏定义 概念 利用 #define 命令,用一个标识符代表一个字符串。已经定义的宏可以用命令 #undef 撤消。 好处 减少重复书写字符串的工作量;易于记忆、理解;程序易修改 。 #include "stdio.h" #define Pi 3.1415926 /*宏定义,用 Pi 代表字符串“3.1415926” */ void main() { int r=4; float i,s,v; i = 2 * Pi * r; /*等价于 i = 2*3.1415926*r; */ s = Pi * r * r; /*等价于 s = 3.1415926*r*r; */ v = 4.0/3 * Pi * r * r * r; /*等价于v=4.0/3*3.1415926*r*r*r; */ printf(“i=%f\ns=%f\nv=%f\n", i, s, v); }
9.1 宏定义 不带参数的宏定义 定义格式: #define 宏名 字符串 宏名,一般用大写字母表示,与变量相区别。 字符串又叫宏体,宏名与宏体之间以空格相隔。 宏定义命令#define应该写在函数外面,其作用域为该命令之后到该源文件结束 注意 宏替换只是一种简单的字符替换,不进行计算,也不作语法检查。不分配内存空间。 对程序中用双引号括起来的字符,即使与宏名相同,也不进行置换。
9.1 宏定义 运行结果: x=10 y=14 #include "stdio.h" #define N 3+4 void main() { int x,y; x = 2*N; y = 2*(N); printf("x=%d\ny=%d\n", x, y ); } 运行结果: x=10 y=14 #include "stdio.h" #define N 3; //出错! void main() { int x; x = 2*N+1; printf("x=%d\n", x ); } 系统提示:编译出错! 宏定义N 代表3; 注意3后面有”;”, 而将“3;”代入表达式中N,当然出错!
9.1 宏定义 带参数的宏定义 作用:不是进行简单的字符串替换,还要进行参数替换。 格式: #define 宏名(参数表) 字符串 字符串中包含在括弧中所指定的参数 例:#define S(a,b) a*b area=S(3,2); 程序中用3和2分别代替宏定义中的形式参数a和b,用3*2代替S(3,2) 。因此赋值语句展开为: area=3*2;
9.1 宏定义 带参的宏定义置换方法 对带实参的宏,如S(3,2),按#define命令行中指定的字符串从左到右进行置换。若串中包含宏中的形参(如a、b),则将程序中相应的实参(可以是常量、变量或表达式)代替形参。如果宏定义中的字符串中的字符不是参数字符(如a*b中的*号),则保留。这样就形成了置换的字符串。
9.1 宏定义 例:使用带参的宏定义。 运行结果: #include <stdio.h> r= 3.600000 #define PI 3.1415926 #define S(r) PI*r*r void main() { float a,area; a = 3.6; area = S(a); printf("r=%f\narea=%f\n", a, area ); } 运行结果: r= 3.600000 area = 40.715038 area = S(a); ” 经宏展开后为:area = 3.1415926 * a * a;
9.1 宏定义 例: 通过宏展开得到若干个结果。 #include <stdio.h> #define PI 3.1415926 #define CIRCLE(R,L,S,V) L=2*PI*R; S=PI*R*R; V=4.0/3.0*PI*R*R*R void main() { float r,l,s,v; scanf("%f",&r); CIRCLE(r,l,s,v); printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v); }
9.1 宏定义 对宏进行预编译,展开后的main函数如下: void main() { float r,l,s,v; scanf("%f",&r); l = 2*3.1415926*r; s = 3.1515926*r*r; v = 4.0/3/0*3.1415926*r*r*r; printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n ", r, l, s, v ); } 3.5↙ r=3.50,l=21.99,s=38.48,v=179.59
9.1 宏定义 运行结果: 3.1415926 3.14 撤消宏定义命令 用命令 #undef 撤消已定义的宏,终止该宏定义的作用。 #include "stdio.h" #define PI 3.1415926 void main() { printf("%f\n", PI ); function(); } #undef PI #define PI 3.14 void function() 运行结果: 3.1415926 3.14
9.1 宏定义 说明 对带参数的宏展开只是将语句中的宏名后面括号内的实参字符串代替#define 命令行中的形参。 在宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。
9.1 宏定义 带参数的宏和函数的区别 函数调用时,先求实参表达式值,然后代入形参。而带参的宏只进行简单的字符替换。 函数调用在程序运行时处理,为形参分配临时的内存单元。而宏展开在编译前进行,不分配内存单元,不传递值,没有“返回值”的概念。 函数中实参和形参类型要求一致。而宏名无类型,它的参数也无类型。宏定义的字符串可以是任何类型的数据。 调用函数只可得到一个返回值,而用宏可以设法得到几个结果。 使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序增长,而函数调用不会使源程序变长。 宏替换不占运行时间,只占编译时间。而函数调用则占运行时间(分配单元、保留现场、值传递、返回)
9.2 文件包含 文件包含 概念:将一个指定文件的全部内容包含到当前文件之中,使这两个源文件连成一个源文件。 使用格式: #include “文件名“
9.2 文件包含 件file1.c,内容为: 示例:若有一个C文 将它包含在如下文件file2.c中: #define PI 3.1415926 #define N 3 #include "stdio.h" #define PI 3.1415926 #define N 3 void main() { float r=4, l, m; l = 2*PI*r; m = N*10; printf("l=%f\nm=%f\n",l,m); } #include "stdio.h" #include "func.c" void main() { float r=4, l, m; l = 2*PI*r; m = N*10; printf("l=%f\nm=%f\n",l,m); }
9.2 文件包含 有些公用的符号宏定义,可以单独组成一个文件,其它文件用“#include”将这些宏定义包含在自己的源文件中,从而避免重复书写,减少出错。我们将一些标准的库文件包含到当前自己编写的程序中,例如常用的#include “stdio.h”等。 注意 一个#include命令只能指定一个被包含文件,如果要包含多个文件,就要用多个#include命令。 在#include 命令中,文件名可以用双引号括起来,也可以用尖括号括起来,例如:#include “stdio.h” 或者 #include <stdio.h>。 但这两者是有区别的,一般用双引号比较保险,不会找不到文件。
9.3 条件编译 概念 所谓“条件编译”,是对部分内容指定编译的条件,使其只在满足一定条件才进行编译。 条件编译命令的几种形式 (1) #ifdef 标识符 程序段1 #else 程序段2 #endif (2) #ifndef 标识符 程序段1 #else 程序段2 #endif (3) #if 表达式 程序段1 #else 程序段2 #endif
9.3 条件编译 例 输入一行字母字符,根据需要设置条件编译,使之能将字母全改为大写输出,或全改为小写字母输出。 #include <stdio.h> #define LETTER 1 void main() { char str[20]="C Language",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); } 运行结果为: C LANGUAGE