感谢:http://www.cnblogs.com/mjios/archive/2013/03/20/2969817.html
一、预处理指令:在编译源文件程序前对源程序进行处理,用#表示该行为编译处理指令。在C语言中加入一些编译预处理指令可以提高编程效率,加快编译速度。
注意:预处理命令不是C语言的一部分,因此每条编译预处理命令不需要以分号来结束。
二、预处理简介
1. C语言在对程序进行编译前,会先对一些特殊的预处理指令作解释(像常见的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理)。之后再进行通常的编译;
2. 为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号;
3. 预处理指令可以出现在程序的任何位置,他的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,他的作用范围就是整个源程序文件;
4. C语言提供的预处理指令有:文件包含、宏定义、条件编译;
三、宏定义 -- C语言标准允许在程序中用一个标识符来表示一个字符串。标识符就是宏名。
1. 不带参数的宏
一般形式
#define 宏名 字符串
#define A 100
// 源程序中所有的宏名PI在编译预处理的时候都会被3.14所代替
#define PI 3
float girth(float radius) {
return 2 * PI *radius;
}
int main(int argc, const char * argv[]) {
float a = girth(2);<pre name="code" class="cpp"><span style="font-family: Arial, Helvetica, sans-serif;"> printf("周长为:%f\n", a);</span>
system("pause");return 0;}
2. 使用习惯与注意
1) 宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法粗无;
2) 对程序中用双引号括起来的字符串内的字符,不进行宏的替换操作:
#define R 10
int main ()
{
char *s = "R"; // 这里的R不会替换成10
return 0;
}
3) 在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开的宏名的源程序进行语法检查
#define I 100
int main ()
{
int i[3] = I; // 这一行在编译预处理的时候并不会报错,不过在编译的时候就会报编译的错了
return 0;
}
4) 宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef命令
#define PI 3.14
/*
.
*/
#undef PI // 这一行之后就无效了
// 源程序中所有的宏名PI在编译预处理的时候都会被3.14所代替
#define PI 3
float girth(float radius) {
return 2 * PI *radius;
}
#undef PI;
//
float girth2(float radius) {
// 这里使用宏替换就会出错了
return 3 * PI *radius;
}
5) 定义一个宏可以引用已经定义的宏名
(typedef定义结构体等类型也是类似的)
#define R 3.0
#define PI 3.14
#define L 2*PI*R
#define S PI*R*R
2. 带参数的宏
1) 一般形式:
#define 宏名(参数列表)字符串
2) 在编译的时候,将源程序中所有宏名替换成字符串,并将字符串中的参数用宏名右边的参数列表中参数替换
#include <stdio.h>
#define average(a, b) (a+b) / 2
int main ()
{
int a = average(10, 4);
printf("平均值:%d", a);
return 0; // 结果就是int a = (10 + 4) / 2;
}
3) 使用注意
1. 宏名与参数列表之间不能有空格,否则空格后面所有字符串都作为替换的字符串。
#define average (a, b) (a+b)/2
int main ()
{
int a = average(10, 4);
return 0;
}
可以从上面看出来的是宏名average与 参数列表(a, b)之间有空格,所有int a = 就变成了
int a = (a, b) (a + b)/2(10, 4); // (a, b) (a + b)/2是宏体, (10,4)是average后面的
2. 带参数的宏展开时,只作简单的字符和参数的替换,不进行任何计算。所以在定义宏时,一般用一个小括号括住字符串的参数;
下面定义一个红D(a),作用是返回2的倍数
#include <stdio.h>
#define D(a) 2*a // 如果定义时候不用小括号括住参数, int b = 2 * 3 + 4;
int main ()
{
int b = D(3+4);
printf("%d", b);
return 0;
}
#include <stdio.h>
#define D(a) 2*(a) // 如果定义时候用小括号括住参数, int b = 2 * (3 + 4);
int main ()
{
int b = D(3+4);
printf("%d", b);
return 0;
}
3. 计算结果最好也用括号括起来
#include <stdio.h>
#define Pow(a) (a) * (a) // 定义一个宏p(a),作用是返回a的平方;不用小括号括住计算结果 int b = (10) * (10) / (2) * (2); 100
int main(int argc, const char * argv[]) {
int b = Pow(10) / Pow(2);
printf("%d", b);
return 0;
}
#include <stdio.h>
#define Pow(a) ((a) * (a)) // 定义一个宏p(a),作用是返回a的平方;用小括号括住计算结果 int b = ((10) * (10)) / ((2) * (2)); 25
int main(int argc, const char * argv[]) {
int b = Pow(10) / Pow(2);
printf("%d", b);
return 0;
}
3. 与函数的区别
虽然带参数的宏出现的形式与函数很像,不过还是有区别的:
1) 宏的定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题;
2) 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数 具有跟高的执行效率;
感谢:http://www.cnblogs.com/mjios/archive/2013/03/20/2969817.html