为什么复杂的宏定义中常见
#defines ... do{ ... } while(0)
而非#defines ... { ... }
其实大家应该都明白#define SQUARE(x) ((x)*(x))
为什么要加括号,就是防止宏替换时候函数不按自己的想法执行,用{}也是想做好封装,其实还是有风险的。
看一个例子就明白了
#define Max(a,b) { (a)>(b)?(a):(b);}
if(1)
Max(2,3);
else
Max(4,5);
看出问题了没,这个函数编译会报错error C2181: illegal else without matching if
,是说else没有对应的if,这怎么可能呢?前面明明有if啊!!!仔细分析会发现平时写if-else语句无非两种格式
if()
func1;
else
func2;
或者
if()
{
func1;
}else
{
func2;
}
但上面的Max不是函数,是宏,被替换后就会变成
if()
{
func1;
};else
{
func2;
}
多出的分号;就把if给截断了,if单独成判断语句和else分家了。所以有前面报错。
进行下面修改
#define Max(a,b) do { (a)>(b)?(a):(b);}while(0)
if(1)
Max(2,3);
else
Max(4,5);
用do-while(0)方式定义宏,完全不用担心使用者如何使用宏,也不用给使用者加什么约束。
P.S.能用函数代替的尽量不要用宏,原因如下:
- 宏使用不当会有意外的副作用,上面便是
- 大量的宏替换占用大量代码空间,不如函数效率高
- debug调试宏内部无法设置断点,不利于问题定位
- 宏缺乏类型检查,不如函数语法检查严格