这几天在看代码的时候遇到了一个好像很神奇的用法:do{ … }while(0)。
do{ … }while(1)我能理解,就是一直循环,然后在循环体内设置跳出条件,或者干脆就不跳出。
那do{ … }while(0)是干嘛的呢?在内部也改变不了循环条件,然后执行一次就结束,那不就是没循环嘛?
赶紧查了一下,原来,这种用法主要是针对宏定义使用的。
这里我们来看一下如下代码:
#define INCREASE_TWO_VARIABLE(a, b) a++;\
b++;
我们定义了一个宏,其中包含了两条语句。看上去好像没什么问题。岁月静好,风平浪静。
但是,再考虑如下情景:
if(some_condition)
INCREASE_TWO_VARIABLE(x, y); //请记住这个分号
else
do_something;
嗯???好像哪里不对??我们把宏定义拆开:
if(some_condition)
x++;
y++;; //这里两个分号一个是宏定义内部的,一个是宏定义外部的。但是此时这里并不会报错,两个分号是可行的
else //报错,没有对应的if语句
do_something;
哎,这里就出现问题了,如果if后面不加大括号,那么只能跟一个语句,其他语句将被视为条件体之外的语句。那么此时,不仅y++一定会被执行,而且else没有对应的if语句,还会报错。(此时还好else会报错,不然编译通过,你却发现程序怎么都跑不对)
那咋办呢?不如我们用大括号把它括起来吧!于是我们修改了宏定义成这个亚子:
#define INCREASE_TWO_VARIABLE(a, b) {\
a++;\
b++;\
}
然后刚才的情景就变成了:
if(some_condition)
{
x++;
y++;
};
else //报错
do_something;
嗯???不是?这个大括号后面的分号是怎么肥四!你在使用宏定义的时候后面就不能不加分号嘛!(请注意最开始的那个分号)
使用者:不,我不可以,我是强迫症!而且不加分号,VS会自动把else缩进4个空格,我还要手动删!
…………于是这个时候,你想起了传说中的do{ … }while(0)。于是你又把宏定义做了一个小小的修改:
#define INCREASE_TWO_VARIABLE(a, b) do{\
a++;\
b++;\
}while(0)
于是刚刚的情景又变成了:
if(some_condition)
do{
x++;
y++;
}while(0);
else
do_something;
于是编译又通过了,世界又恢复了和平。
此外,其实do{ … }while(0)还有另一种用法,虽然我依然觉得好像没什么卵用 :
if(condition1){
do_something();
}
if(condition2){
do_something();
}
if(condition3){
do_something();
}
if(condition4){
do_something();
}
这个时候do_something()会被各种执行,如果这一段代码非常复杂,那么看起来就会非常冗余。
虽然你可以使用宏定义将这些代码合在一起,也可以将condition合在一起变成一个if语句,但是你觉得使用宏定义不爽,合在一起又太乱,所以决定使用do{ … }while(0)。
do{
if(condition1){
break;
}
if(condition2){
break;
}
if(condition3){
break;
}
if(condition4){
break;
}
}while(0)
do_something();
所以总结来说:其实,do{ … }while(0)就是满足强迫症的,不接受反驳,over。
(其实这种用法应该是用来提高代码的一致性,是一种非常好的编程习惯,因为使用者并不会知道你这个宏的结尾该不该加分号)
(如有错漏,还望指摘)