define
#defined定义一个宏
宏替换在预处理阶段完成,宏替换为简单的值替换
总结在最后,不想仔细看就直接看最后面。。。
宏替换一般分为两种
- 无参的宏
#define PI 3.14f
那么程序中遇到PI就直接在编译阶段就全部替换为了3.14了
2.带参的宏
#define MUL(a, b) a*b
在遇到MUL(参数,参数)的时候直接替换为a*b。这样直接写感受不明显,下面用两道题来讲解
#if A == 3
#define B 3
#else
#define B 5
#endif
int main()
{
printf("%d", B);
return 0;
}
这个输出是什么呢?好像一眼看去为printf("%d", B);
,这个B在宏定义中有,但是却在一个判断语句中。假如A==3
那么B==?
,但是在这里就会发现A也没有定义。可能有人会觉得在函数中A自始至终都没有出现过,所以编译不能够完成,其实不然。A没有被定义,默认值为0,0是固然不等于3,所以B被赋值5。
上面两个测试程序就可以看出来,对于宏定义的变量,没有赋值的话是等于0的。
下面这题
#include <stdio.h>
#define ADD(x) x+x
int main()
{
int x;
x = 100/ADD(10);
printf("%d", x);
return 0;
}
宏函数为简单的值替换!这点要牢记
这一句x = 100/ADD(10);
应当替换为x=100/10+10,并不是100/(10+10)
,这里就能看出“简单的值替换了”
结果为20.
再看一题:
# include <stdio.h>
# define scanf "%s Embedded Inn "
int main()
{
printf(scanf, scanf);
return 0;
}
这题是在一个微信公众号上看到的
在预处理阶段,代码将会替换,一旦不小心就会出错!
printf(scanf, scanf);
被替换为printf(“%s Embedded Inn”,“%s Embedded Inn”);
其实当替换到这里的时候,我还在觉得,会不会编译出错
但是,其实是可以的,这里需要提一下,**""这个双引号的作用,不仅可以代表是一个字符串,还可以对这个字符串取地址。**就像return一样,有多个功能。
那么printf(“%s Embedded Inn”,“%s Embedded Inn”);
第一个%s输出的为第二个的字符串
输出的结果为:%s Embedded Inn Embedded Inn
所以在使用宏函数的时候,尽量使用()来保证参数的完整性
#define MUL(a, b) a*b
MUL(3+2, 4+2)==> 3+2*4+2 ==> 13
//使用括号,可以尽量保证参数的完整性,只是尽量哈
#define MUL(a, b) ((a) * (b))
MUL(3 + 2, 4 + 2) ==> ((3 + 2) * (4 + 2)) ==>30
看起来加上()能够正常计算,但是当使用++的时候还是不好使
看下面的代码
#define MAX(a,b) (((a)>(b))?(a)(b))
MAX(2+3,3+5);//这样的使用是没有毛病儿
//但是一旦牵扯到++,--运算
int x=3,y=5;
MAX(x,++y);
//(((x)>(++y))?(x)(++y))----->7
//这样就没有办法,括号也救不了哦,这就是宏替换的固有缺陷
总结:
1.在预处理阶段,实现宏展开 ,没有函数调用出入栈的开销 ,效率高 ,但空间消耗大(典型的空间换时间)。
2.宏函数,尽量包含简短的代码 ,尽量不要有大量判断、循环语句。
3.宏函数不能保证参数的完整性。我们之所以有这么关于宏函数的问题,都是因为它不能够保证参数的完整性,即使加上括号也难以避免。