可以使用#define伪指令定义一个宏,宏分为带参数的宏和不带参数的宏。宏定义以#define关键字后面第一个出现的第一个连续字符序列作为宏,剩下的部分作为宏体。宏定义具有文件作用域,不论宏定义出现在文件中的那个地方(如函数体内,类型定义内部,名字空间内部等),在它后面的任何地方都可以引用宏。
宏的特点和注意事项:
(1)宏定义的不是语句,因此不需要使用语句结束符“;”,否则它会被看做宏的一部分。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define WRITE(x,y) (x+y)
int main()
{
WRITE(2, 3);
printf("%d\n", WRITE(2, 3));
system("pause");
return 0;
}
(2)任何宏在编译预处理阶段都只是进行简单的文本替换,不做类型检查和语法检查,这个工作留个编译器进行。参数替换法生在宏扩展之前。
(3)宏可以嵌套定义。
#define PI 3.14 #define PI_2 (2*PI)
(4)宏不可以调试,因为宏不会进入符号表(符号表是编译器创建的,在编译时宏已经消失了),即使宏替换后出现了语法错误,编译器也会将错误定位在源程序中而不是定位到具体的某个宏定义中。
(5)程序里使用双引号括起来的字符串中即使出现了与宏同名的子串,预处理过程也不进行替换。
(6)定义带参数的宏时,宏名和左括号之间不能出现空格,否则使用时会出现问题,但是编译器不会检查出这种错误。
错误的:
#define TEXT (str)#str
宏引用:
TEXT(hello bit);
扩展为:
(str)#str(hello bit);
正确的:
#define TEXT(str) #str
(7)带参数的宏和各个参数应该分别用括号括起来,以免造成意想不到的错误。
应该写成这样:
#define ADD(x) ((x)+(x))
如果写成:
#define MPLIT(x) x*x
就极有可能因为运算优先级的问题造成错误。语句:
a=MPLIT(3+5);
将被扩展为:
a=3*5+3*5;
很明显出现了错误!
注意:在定义宏的过程中千万不要吝啬括号。
(8)不要在引用宏定义的参数列表中使用自增和自减运算符,否则可能导致变量多次求值,其结果可能与预期不符,因为复合表达式中的求值顺序可能因为编译器的不同而不同。例如:
int n=5;
int w=MPLIT(n++);
其结果可能是25,也可能是30。
(9)带参数的宏并不是函数,因此没有函数调用的开销,但是其每一次扩展都会生成重复的代码,结果使可执行程序的代码体积增大。
(10)当我们不在使用某一个宏时,可以使用#undef来取消其定义,例如:
#undef MPLIT
否则简单的删除宏定义,会带来许多编译的错误。
本文出自 “Stand out or Get out” 博客,请务必保留此出处http://jiazhenzhen.blog.51cto.com/10781724/1712803