不能忽视宏定义中的空格
//#define f (x) ((x)-1) f 表示 (x) ((x)-1)
#define f(x) ((x)-1)
宏不是函数
#define abs(x) (((x)>=0)?(x):-(x))
#define max(x,y) ((x)>(y)?(x):(y))
宏定义中的括号作用是 预防引起与优先级有关的问题
- 当一个操作数在两处被用到,被两次求值,如:
max(biggext,x++)
将宏展开后为
((biggext)>(x++)?(biggext):(x++))
x的递增操作进行了两次,程序编译没有错误,运行出错
- 宏展开可能产生庞大的表达式
宏不是语句
#define assert(e) if(!e) assert_error(_FILE,_LINE_)
if(x > 0 && y > 0)
assert(x > y);
else
assert(y > x);
展开后变为:
if( x > 0 && y > 0)
if(!(x > y))
assert_error("foo.c",37);
else
if(!(y > x))
assert_error("foo.c",39);
断言assert宏的正确写法:
#define assert(e) ((void)((e))||_assert_error(__FILE__,__LINE__)))
y=distance(p,q);
assert(y>0)
x=sqrt(y);
利用||运算符对两侧操作数依次顺序求值的性质
当e为true时,右侧表达式
_assert_error(__FILE__,__LINE__)
就不会进行计算
当e为false时,右侧表达式必须进行求值,_assert_error被调用,打印一条恰当的“断言失败”的消息
宏不是类型定义
#define T1 struct foo *
typedef struct foo *T2
T1 a,b;
//展开为strcut foo *a,b;
//a为指向结构体foo类型的指针变量, b为结构体foo类型的变量
T2 c,d;
//c和d均为指向结构体foo类型的指针变量