目录
前言
提起预处理,第一时间想到的大多都是类似于头文件的引入,但这里面其实大有可说。
比如:
printf("%s\n", __DATE__);
printf("%s\n", __TIME__);
这是编译器自己设置的⼀些预定义符号,无需定义可以直接使⽤,现在问:这些printf打印出了什么内容?
一、#define机制
1.#define 定 义 常 量
#define MAX 0
编译器看到这行代码后,会把使后续代码中除了字符串中的MAX,其余出现的MAX都会被替换成“0”,比如“printf("MAX=%d",MAX);”——>“printf("MAX=%d",0);"
作者在学到这时曾有疑问:“#define MAX 0”后面需要加“;”吗?看上去加不加似乎都无伤大雅,
但作者建议不要在#define语句后加上“;”,就拿上面的那条语句说:若是在后面加上“;“变成#define MAX 0;
那编译器在编译printf("MAX=%d",MAX);时就会报错,原因是在预处理阶段MAX已经被替换成“0;”了,相当于printf("MAX=%d",0;); 显然这里出现了语法错误。
以下代码报错的原因是?
#define X 7;
int main()
{
int a = 0;
if (1)
a = X;
else
printf("goodby");
}
if-else语句如果没加{}则每个只能写一条语句,即只能有一个“;”,这里的X自带一个";",后面又加一个“;”,故编译器报错。
现在接前言:
__DATE__,其值是执行这段程序的日期;
__TIME__是执行这段代码的时间;
除此之外还有__FILE__,值是当前文件所在目录;
__LINE__,值是当前代码行数。
等等...
注意:在使用#define时有个不成文的规定,名字一般都为大写
2.#define 定 义 宏
规则:#define定义机制允许把参数也替换到文本中
比如:
#define SQU(x) x*x
注意:参数的左括号需与名紧密相接,不能有空号。现在可以在文中使用以下代码:
int x=2;
int z =SQU(x);
printf("%d",z);
原理是:编译器会在预处理阶段把SQU(x)替换为x*x。 所以打印出的 z的值 自然是 4。
但这样做也是有风险的:
请考虑将上述第二行代码转变为int z = SQU(2 + 1); ,这样z的值会是多少呢?9吗?
我们顺着思路将int z = SQU(2 + 1);替换为编译器处理过后的内容:int z =2 + 1 * 2 + 1;
现在明确了,原来是运算符的先后次序不同导致的,解决这个问题:在宏定义上加上两个括号就可以了。
#define SQU(x) (x)*(x)
再看以下代码未实现目标的原因:
#define ADD(x) (x)+(x)
int a = 5;
int b = 10 * ADD(5);
printf("%d",b);
b的结果是55,而不是100。编译器处理后变成了int b = 10 * (5)+(5);
改为#define ADD(x) ((x)+(x))这样定义即可。
作者建议在定义宏时不 要 吝 惜 括号“()”。
二、宏与函数的对比
认识了宏后感觉宏与函数非常相似,那么他们的区别是?
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int z = MAX(3, 5);
printf("%d", z);
return 0;
}
上述代码是定义成宏好呢,还是封装成函数好呢?
1.宏对比函数的优点
1.所耗时间少:若使用函数实现上述代码,则函数的调用、参数的传递、函数的返回所用的时间是大于用宏实现该段代码的,毕竟使用宏时编译系统是直接把代码“复制粘贴”在原处。所以宏在
2.无需重复定义函数:函数参数的类型决定了该函数的使用范围,若形参为int型,则float型数据就无法使用该函数,,而使用宏是与参数类型无关的,没有这种顾虑。
2.宏对比函数的劣势
1.宏无法调试:在明白宏生效的途径后,当即明白宏是没办法调试的。
2.宏会大幅增加代码长度:若是每调用一次宏,编译器就“复制粘贴”一份,那代码的长度将会大幅增加,给维护带来不便。
请看以下代码 :
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int x = 3, y = 5;
int z = MAX(x++, y++);
printf("x=%d y=%d z=%d",x,y,z);
return 0;
}
这段代码完成后,x=4,y=7,z=6;
3.宏可能会带来运算符优先级的问题以及永久改变参数值的问题
但宏有时能做到函数难以完成的事:
#include<stdlib.h>
#include<stdio.h>
#define MALLOC(num,type) (type*)malloc(num,sizeof(type))
int main()
{
int* pf = MALLOC(3, int);
if (pf == NULL)
{
return 1;
}
free(pf);
pf = NULL;
return 0;
}
这里编译器预处理之后变成:int * pf=(int*) malloc(3,sizeof(int));