- 宏通常被应用于执行简单的算法,比如找出两个数中的最大值:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define Max(x,y) x>y?x:y
int main()
{
int a = 0;
int b = 0;
int c = 0;
printf("Enter a:");
scanf("%d", &a);
printf("Enter b:");
scanf("%d", &b);
c=Max(a, b);
printf("%d\n", c);
system("pause");
return 0;
}
代码运行如下:
这个代码不可以用函数完成?
当然可以用函数,只是宏比函数在这个代码中更加有优势:
1:代码非常简单,使用宏直接在编译(预处理)期间就替换了变量c,而函数要调用以及返回,这些时间可能比代码执行的时间还要多;
2:宏可以用于整形,长整型,浮点型等可以用>来比较的类型,与类型无关;但是函数的参数必须声明为特定的类型;
- 宏还可以干一些函数做不到的事情,比如宏参数可以出现类型,但是函数不可以。
#define MALLOC(num,type) (type*)malloc(num*sizeof(int))
malloc(10,int)即向内存申请10个类型为int型的内存;
当然宏也有劣势:
- 使用宏时,除非代码很短,否则会造成篇幅大度增长,比如宏有20行,被调用20次,就会使代码增加400行;
- 宏没有办法调试,比如由于宏少带括弧造成的运算错误,调试时没有办法确定错误的位置;
- 宏与类型无关,当然也就不够严谨;
- 宏可能会带来运算符优先级的问题,导致程序容易出现错误。
观察下面代码:
#define SQUARE(x) x*x
…………
int a=5;
printf("%d\n",SQUARE(a+1));
乍一看觉得会打印36这个值。
事实上它将打印11。
为什么呢?
替换文本时,参数x被替换为a+1,所以语句变成了a+1*a+1,a=5,所以打印11
在宏定义上加两个括号,这个问题便解决了。
这里还有一个宏定义:
#define DOUBLE(x) (x)+(x)
…………
int a=5;
printf("%d",10*DOUBLE(a));
在定义中我们使用了括号,想避免之前的问题,但是这个宏又出现了新的错误,看上去好像打印100,但事实上打印了55,
我们发现替换文本之后变成10*(5)+(5),乘法运算级高,所以出现了55。
在宏定义上加两个括号,这个问题便解决了。
提示:所有对于数值表达式进行求值的宏定义都应该用这种方式加括号 ,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
带有副作用的宏:(包含i++,i--等)
#include<stdio.h>
#include<stdlib.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int x = 5;
int y = 8;
int z = MAX(x++, y++);//后置++,先使用后加1;
printf("x=%d y=%d z=%d ", x, y, z);
system("pause");
return 0;
}
这段代码我们期望输出x=6,y=9,z=8;
运行结果:
正是因为宏的副作用导致出错,预处理后:z=((x++)>(y++)?(x++):(y++))
后置++(先使用后++),5>8不成立:x=6,y=9,输出z=9,y++变成10;
所有在使用宏时可能存在危险,导致不可估量的错误;
命名约定
把宏名全部大写
函数名不要全部大写
宏和函数的区别
- 一个简单的例题:使用宏将一个数的奇数位和偶数位互换
#include<stdio.h>
#include<stdlib.h>
#define exchange(a) ((a&(0x55555555))<<1)|((a&(0xAAAAAAAA))>>1)
int main()
{
int a = 5;
int b = exchange(a); //取出奇数位右移一位,偶数位左移一位
printf("%d\n", b);
system("pause");
return 0;
}
代码思路:
取出奇数位:a&10101010101010101010101010101010
取出偶数位:a&01010101010101010101010101010101
奇数位右移一位到偶数位,偶数位左移一位到奇数位;
由于二进制数太多,会导致常量太大,所以可以将二进制改成十六进制;
运行如下: