牛骨文教育服务平台(让学习变的简单)

其实关注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不会那么痛苦。

  1. 跳出代码块,不执行后面的语句

其实这个功能比较实用一些

很多的条件判断可以用到do{}while(0)的写法

这个用法其实也很简单,精髓就在于用break或者continue来控制流程,跳出代码块。

就像下面的一串代码,看看就能明白了:

bool bFlag = false;
do {
      if (!bFlag) {
      print("The flag is FALSE");
      break;// 用break(continue)跳出了之后就不用执行下面的语句了
      //continue;
    }
   print("Work off.
");
} 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
", (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
", (INT)byProtocol, nSize, nProSize);
	//协议出错跳出
	if (nProSize != nSize){
		printf("Invalid ProtocolType %d, Size:%d != ProSize:%d
", (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)我也就只学习到这里。