之 编译预处理与宏定义
宏是编译预处理的重要定义,宏定义就像基本数据类型定义同样,能够看做是一种类型,与基本类型不一样的是,宏与函数有着密切的类似之处,可是宏是编译时发生做用。
1. 通常格式:
#define 标识符 字符串 标识符即为这个字符串的宏名
2. 宏调用:程序中用宏名代替字符串。
宏展开:预编译时将字符串代替宏名的过程。
好比:#define PI 3.14
这里的PI就是宏名,他表明的是字符串3.14,预编译时将源程序中的全部宏名PI出现的位置都用字符串3.14来替换。好比: 程序中出现PI*5,它的结果其实是 3.14*5
(1)宏名用大写,用来区分普通变量
(2)宏定义不能以分号结束,不然分号将做为字符串的一部分参加宏展开。好比:
#define PI 3.1415; //结尾加了分号
a=PI*r*r;
|
在编译预处理时,将宏展开: a=3.1415;*r*r 分号将做为字符串参加运算,很明显是错误的
(3)宏定义只是用来替换字符串的。 无论字符串是什么数据类型,总之就是一句话,宏名替换字符串,宏名替换的必定是字符串,即便上述中的3.1415写成了3.1W15。替换后的结果依然是a=3.1W15*r*r。
(4)#define命令定义的宏名范围是从定义命令开始直到源程序文件结束,并且#define定义在文件开头与函数之间。 若是要想提早结束宏定义的做用域,能够经过#undef终止宏名的做用域
(5)宏定义中能够出现已经定义的宏名,能够层层置换。
若宏名中 出现一个被双引号括起来的字符串中时,将不会产生宏替换。
好比:
#include <stdio.h> /*宏定义在文件头和函数之间*/ #define R 3.0 #define PI 3.1415926 #define L 2*PI*R //出现了前面已经定义的PI和R #define S PI*R*R //出现了前面已经定义的PI和 main() { /* 当L和S在“”以内时将不会与宏定义产生联系,即不会发生替换 当L和S不在“”以内时,L将被替换成 2*PI*R,S将被替换成 PI*R*R */ printf("L=%7.2f\nS=%7.2f\n",L,S); } |
最后须要注意的是: 宏定义是专用于预处理的一个名词,它的做用就是替换,不分配空间
通常格式:
#define 宏名(参数表) 字符串
带参数的宏定义并不单单是宏名代换字符串,还要进行参数的替换,相似于函数的调用
好比:
#define S(a,b) a*b
area=S(3,2);
|
S为宏名,a和b为形参,程序中调用S(3,2),把实参3和2分别替换形参a和b,因此宏展开是area=3*2;
好比:
#include <stdio.h> /*宏定义在文件头和函数之间*/ #define S(a,b) a*b //须要注意的是S和()之间不能有空格 main() { int area; area=S(2,3);//传递给宏S(a,b),而后替换为a*b printf("area=%d\n",area); } |
(1)上述程序中的参数传递应该很好理解,可是若是把程序改动一下,让实参的值变成S(2+3,3+4), 你们确定会认为是35,可是真的是35吗? 咱们看一下:
#include <stdio.h> /*宏定义在文件头和函数之间*/ #define S(a,b) a*b //须要注意的是S和()之间不能有空格 main() { int area; area=S(2+3,3+4); printf("area=%d\n",area); } |
居然是15,并非咱们想象中的35,怎么回事呢? 实际上S(2+3,3+4)传递过去后,它的红替换是 area=2+3*3+4,这下你们明白了吧。仍是一句话,宏定义只是用来替换的,完彻底全的原样的替换。那要怎么解决这个问题呢?很简单,在宏定义的时候加上一个括号就能够了,看程序:
#include <stdio.h> /*宏定义在文件头和函数之间*/ #define S(a,b) (a)*(b) //须要注意的是S和()之间不能有空格 main() { int area; area=S(2+3,3+4);//传递给宏S(a,b),而后替换为a*b printf("area=%d\n",area); } |
(2)宏定义的宏调用与函数调用的区别
在学习了带参数的宏定义后,是否是以为这个调用与函数的调用很类似,可是它们彻底是不通的两个概念:
函数调用时,先求出实参表达式的值,再将该值传递个形参,而带参数的宏调用只是进行替换,简单的字符替换
函数调用是在程序运行时处理,分配给形参临时内存单元,而宏展开则在编译时进行的,展开的时并不给形参分配内存单元,不进行值传递,也没有返回值