c语言中宏是一个在预处理中使用的方法,宏可以完成类似函数的功能,但是宏和函数又有很多的不同,在这里记录一下宏的概念和用法。
首先定义一个宏是用#define 名字(参数) 功能,例如下面定义了一个可以实现加法的宏
#include<stdio.h>
#define MUL(x,y) x * y
int main()
{
int a = 2;
int b = 3;
int c = add(a, b);
printf("%d", c);
return 0;
}
在定义宏是默认都是以全大写来取的名字,这些细节要注意,在这里向里面传递a,b,实现了两个数相乘
但是只是这样写是不够的,因为宏是再预处理阶段将传入的值直接替换,这样写会出现很多问题,例如:
#define MUL(x,y) x * y
int main()
{
int a = 2;
int b = 3;
int c = add(a+1, b+1);
printf("%d", c);
return 0;
}
如果我们的参数传的是a+1,b+1,那么问题就出现了,我们想算的是3*4,但是这个程序的结果却是6,从这里就可以看出宏和函数的不同,宏是再预处理中完成一模一样的交换的,如果我们像上面这样写,相当于我们写了这样一个代码:
int c = a + 1 * b + 1
在我们的代码还没有运行的时候,宏会将参数原封不同地进行替换,由于乘号的优先级比加号高,因此得出了不是我们预想的结果,那可以这样改进:
#define MUL(x, y) (x) * (y)
改后就相当于我们写了这样一个代码:
int c = (a + 1) * (b + 1)
在宏的参数上加上括号可以有效地避免计算顺序的错误
主要是我们可以理解宏是再预处理阶段就将算法给替换了,一些出错的问题自然也明白了,又像这样的错误:
#define ADD(x, y) x + y
#define RADD(x, y) (x + y)
int main()
{
int a = 2*ADD(2, 3)
int b = 2*RADD(2, 3)
return 0;
}
使用这个宏的人大都想要执行2乘以2和3的和这样的运算,但a却得出了7的结果,b才是得出10,这个也是因为预定义是进行直接替换导致运算顺序不是我们理想中的顺序导致的错误,这个a相当于a=2*2+3,因此我们在使用宏的时候一定要注意这些问题,把参数用括号括起来可以避免一些我们有时候会忽略的错误。
还有一个宏可以实现函数不能实现的功能就是宏比较自由,如:
#define print(a, b) printf("the number of " #a " and " #b " is %d", (a)+(b))
int main()
{
int a = 10;
int b = 20;
print(a, b);
return 0;
}
在这里我们用宏来进行两个数的相加还有打印,这里重要的是#a这个写法,#a会自动地将你传过来的参数转换为一个字符串,而不会替换为数字,这意味着无论我们传过去的参数名字是什么,这个宏都可以打印出这个参数的名字,还要个重要的是如果我们不但想计算整形数据,偶尔也想计算浮点型数据,那么函数就需要将形参改变为浮点型数据,但是宏由于是在预处理将其替换,我们就不需要考虑数据类型的问题,这个算是宏相对于函数的一个好用的地方,上面我们写的代码相当于这样:
int main()
{
int a = 10;
int b = 20;
printf("the number of " "a" " and " "b" " is %d", (a)+(b));
return 0;
}
由此可见无论我们传的是整形数据还是浮点型的数据都可以完成加法功能。
一个#是将传入的参数转换为字符串,两个#就是将两部分连接起来,例如:
#define full(frist, last) frist##last
int main()
{
int number = 10;
printf("%d", full(num, ber));
return 0;
}
这里就将传进去的num和ber连接在一起,这句打印在预处理完了之后相当于这样:
printf("%d",number);
这样就可以打印number的数值了
宏的知识先讲到这里,有空再写。