一、预备知识一个项目可以通过编译、链接最终形成一个可执行文件。每个源文件(.cpp)都会单独编译,编译成一个目标文件(.o,也可能是.obj,扩展名跟操作系统有关)。然后系统把这些.o文件进行链接,最终形成一个可执行文件。编译做的事:词法、语法的分析,目标文件(临时文件).o,.obj的生成,优化之类的,这个编译我们可以拆开来看他干了几个事,一般来讲会干这几件事:a.预处理;b.编译:词法、语法分析,目标代码生成,优化,产生一些临时文件。c.汇编:产生.o/.obj目标文件预处理:在源程序.cpp中加入一些特殊的代码(特殊的命令),这些特殊代码有一些特殊的能力,提供一些特殊功能,编译系统会先对这些特殊代码做处理,就叫做“预处理”。处理结果再和源程序代码一起进行上边的 b 的编译,c的汇编这一系列操作。C语言提供三种预处理功能:1、宏定义2、文件包含3、条件编译这三种功能也是通过在程序代码中写代码来实现的,只不过这些代码比较特殊,都是以#开头。二、不带参数的宏定义用一个指定的标识符来代表一个字符串;一般形式:#define 标识符 字符串//标识符也叫宏名[注意:结尾不需要分号]#include //不带参数的宏定义:用PI来代替3.1415926 #define PI 3.1415926//程序源码中,我们写的是PI,在编译预处理的时候,所有在该#define之后的PI都会被替换成“3.1415926” int main() { printf(“%f\n”,PI);//相当于替换为printf(“%f\n”,3.1415926); float ftmp; ftmp=2*PI; //相当于替换为ftmp=2*3.1415926; 这种替换不做语法检查,替换完之后直接参与乘法运算 printf(“ftmp=%f\n”,ftmp); } 好处:A、用一个简单的名字代替一个长字符串,所以这个标识符也被称为宏名,在预编译时将宏名 替换成字符串的过程叫”宏展开”,#define 就是宏定义命令。B、增加了修改的方便性,为修改提供了极大的便利,这种便利被很频繁地使用。也叫提高了程序的可移植性。 说明:(1).宏名(PI) 一般都用大写字母,这是一种习惯,建议都有这样的习惯;(2) 宏定义 不是C语句,所以不必在行末尾加分号,如果加分号则连分号会被一起替换掉。(3) #define 命令出现在程序中函数的外面(一般在.cpp文件最上面,#include下面,函数声明的上面),宏名 的有效范围是 #define 之后,到本源文件结束,不能跨文件使用。(4) 可以用 #undef 命令终止宏定义命令(5) 用#define 进行宏定义时,还可以引用已经定义的宏,可以层层置换(6) 字符串内的字符,即使与宏名相同,是不会进行替换的char stmp[20] =”DPICPI”; //这里不会替换成 2*3.1415926 *3.1415926 三、带参数的宏定义 一般形式:#define 宏名(参数表) 字符串也是用右边 字符串 代替 宏名(参数表) 一般”字符串”中都会包含参数表中所指定的参数,但是不包含也可以,如果不包含,通过参数表传递进去的这个参数干嘛呢,例如:#define S(a,b) a*2 ,那么这里的这个b传递参数进去有什么用呢 #include #define S(a,b) a*b//带参数的宏定义 int main() { int tam=S(2,3);//把2,3分别代替宏定义中的形式参数 a,b ==> S(2,3)==> 2*3 printf(“tam=%d\n”,tam); } 总结:带参数的宏定义是这样展开置换的:对一般形式中的“字符串”,如果字符串中有 宏名后列出的参数如(a,b),则将程序语句中相应的实参(可以是常量、变量、表达式)代替形参;如果字符串中的字符不是参数字符,则保留。 #include //不带参数的宏定义:用PI来代替3.1415926 #define PI 3.1415926 #define S(r) PI*r*r int main() { float area; area =S(3.6);//替换为:3.1415926*3.6*3.6 printf(“圆的面积是:%f\n”,area); //说明: //a、如果输入 area =S(1+5); //表示替换为:3.1415926*1+5*1+5 我们希望的是:3.1415926 * (1+5) * (1+5) //可以这样做:在形式参数外面增加一个括号就可以了 ==> #define S(r) PI*(r)*(r) //b、宏定义的时候宏名和带参数的括号之间不能有空格,否则空格以后的字符都作为代替字符串的一部分了。 //#define S (r) PI*r*r S后面不能加空格 }宏定义和函数的区别:(1) 函数调用时,先求出实参表达式的值,然后带入形参,带参数的宏只进行简单的字符替换;(2) 函数调用是在程序运行时处理,分配临时内存;而宏展开,是在编译时进行的,展开时是不分配内存,也没有返回值这种说法,也没有值传递这种说法。(3) 宏的参数没有类型这一说法,只是一个符号,展开时带入到指定字符串中。(4) 使用宏次数多时,宏展开后源程序变长,函数调用不会使源程序变长;(5) 宏替换只占用编译时间,不占用运行时间,而函数调用占用的是运行时间(分配内存,传递参数,执行函数体)。 有时候会用宏来替换复杂的语句: 例如:用来替换比较两个数的大小:#define MAX(x,y) (x)>(y)” /> 宏替换多行语句: #define MACROTEST do {printf(“test\n”);} while(0) 也可以这样写#define MACROTEST do { \ //加上 \ 表示和下面的是一行printf(“test\n”); \} while(0) /*宏替换比较两个数的大小*/ #include #define MAX(x,y) (x)>(y)?(x):(y)//这里加上括号以防止出错 int main() { int result=MAX(3,6);//替换成 (3)>(4)?(4):(4) printf(“result=%d\n”,result); }/*宏替换多行语句*/ #include #define MACROTEST do { printf(“test\n”);}while(0) int main() { MACROTEST;//相当于替换为 do { printf(“test\n”);}while(0) }