do{}while(0)的妙用
最后更新于:2022-04-01 20:13:20
其实关注do{}while(0)的用法还是一次偶然的机会
当时还在实习,连个工作都找不到,面试的时候有个面试题。
请问do{}while(0)这样写有什么作用?
我当时想这有什么作用,就是里面的代码块执行一遍就是了呗,费劲,胡乱答了几句在上面。
虽然那公司把我录了,但是真的还是很坑的一家公司,呆了两个月自己闪人了。
后面觉得这问题奇怪,就在网上搜了很多关于do{}while(0)用法的文章来看。
总体的作用就是一下几个方面:
1. 辅助定义复杂的宏,避免引用的时候出错
下面是Cocos2dx的一个宏定义:
~~~
#define CC_SAFE_DELETE(p) do { if(p) { delete (p); (p) = 0; } } while(0)
~~~
不得不说Cocos2dx的源码写得还是很严谨的
但是假设这里去掉do{}while(0)和里面的if(p)然后变成下面的这个样子:
~~~
#define CC_SAFE_DELETE(p) delete (p); (p) = 0;
~~~
如果用这个宏定义在代码中使用,像以下代码
~~~
if(NULL != p)
CC_SAFE_DELETE(p)
else
wordOff();
~~~
这段代码就有问题了:
a. 因为if分支后面有两条语句了,所以编译就会出问题。这里如果养成好习惯别装大神,加上一对{}这个问题也可以解决。
b. 还有个问题就是如果没有else分支里面的(p)=0会永远执行。因为if后面没括号只执行紧邻的一句代码。
我们在写代码的时候可以让代码严谨细致一点,加一点括号多两行,但是你以后修改Bug不会那么痛苦。
2. 跳出代码块,不执行后面的语句
其实这个功能比较实用一些
很多的条件判断可以用到do{}while(0)的写法
这个用法其实也很简单,精髓就在于用break或者continue来控制流程,跳出代码块。
就像下面的一串代码,看看就能明白了:
~~~
bool bFlag = false;
do {
if (!bFlag) {
print("The flag is FALSE");
break;// 用break(continue)跳出了之后就不用执行下面的语句了
//continue;
}
print("Work off.\n");
} while (0);
~~~
这里的break跳出循环就有点类似于goto语句了,不过goto太粗糙。
可以自己写个do{}while(0)的代码语句来调试调试,自然而然就领悟了。
还是邓大爷那句话啊,实践是检验真理的唯一标准。
下面是我的项目中通信块用到的do{}while(0)的示例,可以看看加深印象。
~~~
do
{
BYTE byProtocol = *(LPBYTE)pMsg;
if (byProtocol <= S2C_BEGIN || byProtocol >= S2C_END){
printf("Invalid Protocol %d\n", (INT)byProtocol);
assert(false);
continue;
}
INT nProSize = GetProtocolSize(byProtocol);
if (nProSize == -1){
nProSize = PROTOCOL_MSG_SIZE + (*(USHORT*) (((CHAR*)pMsg) + PROTOCOL_MSG_SIZE));
}
printf(">>>>ProtocolType %d, Size:%d != ProSize:%d\n", (INT)byProtocol, nSize, nProSize);
//协议出错跳出
if (nProSize != nSize){
printf("Invalid ProtocolType %d, Size:%d != ProSize:%d\n", (INT)byProtocol, nSize, nProSize);
assert(false);
continue;
}
//网络断开
if (!ProcessFunc[byProtocol]){
assert(false);
continue;
}
if(GHLandProtocol::m_pGameSence!=NULL){
(this->*ProcessFunc[byProtocol])(pMsg, nSize);
}
} while(FALSE);
~~~
好了,关于do{}while(0)我也就只学习到这里。
';