do {} while(0) 常见的两种用法
1.宏定义的多行定义;
2.代码的跳转,使用break跳过某些代码块。
用法1. 宏定义中定义多行
参考:https://bruceblinn.com/linuxinfo/DoWhile.html#:~:text=You%20may%20see%20a%20do,single%20statement%20can%20be%20used.
例子:
定义多行宏
#define foo \
statement_1; \
statement_2
调用宏
if (condition)
foo;
实际会解释成下边这样,是不对的
if (condition)
statement_1;
statement_2;
如果替换成 do() {} while(0) 的形式就可以解决这个问题
#define foo \
do { \
statement_1; \
statement_2; \
} while (0)
这样解析后就变成
if (condition)
do {
statement_1;
statement_2;
} while (0);
性能方面,编译器会自动优化掉 while(0),所以不会造成额外的性能损失,gcc 提供了一种代替的新写法,如下
#define foo ({ \
statement_1; \
statement_2; \
})
用法2. 实现某些代码段的跳过
以 cocos 的一段源码作为示例,因为代码在 do {} while(0) 中所以可以在任意位置使用 break 跳出代码段。
void func() {
bool reinited = false;
do {
if (CURLE_OK != errCode) {
wrapper.second->setErrorProc(DownloadTask::ERROR_IMPL_INTERNAL, errCode, curl_easy_strerror(errCode));
break;
}
// if the task is content download task, cleanup the handle
if (wrapper.second->_headerAchieved) {
break;
}
// the task is get header task
// first, we get info from response
if (false == _getHeaderInfoProc(curlHandle, wrapper)) {
// the error info has been set in _getHeaderInfoProc
break;
}
// after get header info success
// wrapper.second->_totalBytesReceived inited by local file size
// if the local file size equal with the content size from header, the file has downloaded finish
if (wrapper.second->_totalBytesReceived &&
wrapper.second->_totalBytesReceived == wrapper.second->_totalBytesExpected) {
// the file has download complete
// break to move this task to finish queue
break;
}
// reinit curl handle for download content
curl_easy_reset(curlHandle);
_initCurlHandleProc(curlHandle, wrapper, true);
mcode = curl_multi_add_handle(curlmHandle, curlHandle);
if (CURLM_OK != mcode) {
wrapper.second->setErrorProc(DownloadTask::ERROR_IMPL_INTERNAL, mcode, curl_multi_strerror(mcode));
break;
}
reinited = true;
} while (0);
if (reinited) {
continue;
}
curl_easy_cleanup(curlHandle);
DLLOG(" _threadProc task clean cur handle :%p with errCode:%d", curlHandle, errCode);
}