1、起因:
今天看代码时,看到有个宏定义是这样的:
#define setup_timer(timer, fn, data) \
do { \
static struct lock_class_key __key; \
setup_timer_key((timer), #timer, &__key, (fn), (data));\
} while (0)
当时比较疑问为啥这个宏定义要加个do{ }while(0),直接{}不行吗?
后来一查才发现有大学问,下面分析:
2、用do{}while(0)的原因
最主要的就是:帮助定义复杂的宏以避免错误
举例,假如上述函数被按照下面调用:
定义如下:
#define setup_timer(timer, fn, data) \
{ \
static struct lock_class_key __key; \
setup_timer_key((timer), #timer, &__key, (fn), (data));\
}
调用如下:
if()
setup_timer(); ///只有1条语句,有很多人不加{};此时展开的时候多了个;导致逻辑和编译错误
else
do sth.;
展开后是:
if()
{
static struct lock_class_key __key;
setup_timer_key((timer), #timer, &__key, (fn), (data));
} ; //这里出错
else
do sth.;
可以看到当setup_timer()展开后,最后}后面会多个“;”,这会导致if语句被截断而产生错误!!!
当用do{}while(0)时,就可以合理的规避这个书写错误!!!
说不定还有其他可能的错误就不一一举例了!!!!!
3、do{}while(0)其他秒用
3.1 避免使用goto控制程序流
在一些函数中,我们可能需要在return语句之前做一些清理工作,比如释放在函数开始处由malloc申请的内存空间,使用goto总是一种简单的方法:
int foo()
{
somestruct *ptr = malloc(...);
dosomething...;
if(error)
goto END;
dosomething...;
if(error)
goto END;
dosomething...;
END:
free(ptr);
return 0;
}
将goto替换掉的一种书写方法如下:
int foo()
{
somestruct *ptr = malloc(...);
do
{
dosomething...;
if(error)
break;
dosomething...;
if(error)
break;
dosomething...;
}
while(0);
free(ptr);
return 0;
}
实际中经常遇到这样情况代码
有的分支直接退出,有的分支还需后续处理这样子,考虑do{}while(0)
int foo()
{
somestruct *ptr = malloc(...);
do
{
dosomething...;
if(error)
break;
dosomething...;
if(error)
return; //有的分支直接退出,有的分支还需后续处理这样子,考虑do{}while(0)
dosomething...;
}
while(0);
free(ptr);
return 0;
}