一、#define定义标识符
//基本语法:
#define name stuff
//举例:
#define MAX 100
#define reg register
#define print printf("hello world")
#define do_forever for(;;)
define定义常量的逻辑:
在后面的代码中遇到name就用stuff替换掉
二、 #define定义宏
#define 允许把参数替换到文本中,这种实现与函数很类似,通常被称为宏
//申明方式
#define name(parament) stuff//注意name和(参数)之间不能有空格,否则就变成定义标识符了
//举例:
#define ADD(a,b) ( (a) + (b) )
#define SQUARE(x) ( (x) * (x) )
#define MAX(a,b) ( (a) > (b) ? a : b )
你或许会好奇为什么要加这么多括号?这些括号似乎没什么必要,那么,我们把去掉如何?
观察下面代码块:
#define SQUARE(a) a * a
int a = 5;
printf("%d", SQUARE(5 + 1));
//输出结果会是36吗?
为什么呢?其实原因很简单,还记得上面讲#define定义标识符是将name替换成stuff吗?这里也是如此,SQUARE(5+1)在我们看来是传入了参数6,但在宏看来是传入了参数5+1并替换掉参数a
//函数就变成了
printf("%d", 5 + 1 * 5 + 1);
//此时只需要给参数加上括号即可解决
#define SQUARE(a) (a) * (a)
//函数就变成了
printf("%d", (5 + 1) * (5 + 1));
这里还有一个宏定义,即使给参数加上了括号也会出现问题:
#define DOUBLE(a) (a) + (a)
printf("%d", 10 * DOUBLE( 5 ));
在宏看来,这个函数就等同于
printf("%d", 10 * (5) + (5) );
要想解决这个问题也很简单,就是把宏的计算结果再括起来就行
#define DOUBLE(a) ( (a) + (a) )
//函数就变成了
printf("%d", 10 * ( (5) + (5) ) );
三、宏的一些注意事项
- 当宏参数在宏的定义中出现超过⼀次的时候,如果参数带有副作用(a++这种),表达式求值的时候出现的永久性效果。
- 宏定义中可以出现其他宏,但不能出现自己(可以嵌套,不能递归)
- 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
- 宏通常被应用于一些简单的计算,比如输出a和b中的较大的一个
四、宏和函数的对比
优势:
- 宏是直接替换程序内容,相较于函数的调用和输出,一般情况下运行速度更快,规模更小
- 函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使⽤。反之这个宏可以适用于整形、长整型、浮点型等可以用来比较的类型。宏是类型无关的。
劣势:
- 每次使用宏的时候,⼀份宏定义的代码将插⼊到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
- 宏没法调试
- 宏由于类型无关,就不够严谨
- 宏可能会带来运算符优先级的问题,导致程序容易出错