do{}while(0) 的作用

cocos2d-x 源码 中,有大量的这种 do{}while(0) 的用法,例如这个:

        do
        {
            CCImage* pImage = new CCImage();
            CC_BREAK_IF(NULL == pImage);
            bRet = pImage->initWithString(text, (int)dimensions.width, (int)dimensions.height, eAlign, fontName, (int)fontSize);
            CC_BREAK_IF(!bRet);
            bRet = initWithImage(pImage);
            CC_SAFE_RELEASE(pImage);
        } while (0);

根据语意,这样写至少保证do后面的代码块执行一次。

这样写的意义是什么?为什么不直接使用块,而一定要加上 do while 循环?

阅读 14.7k
评论 更新于 2014-07-17
    5 个回答
    King
    • 1.4k

    发现这个问题一搜一大堆哦,题主确定不是SF的托么,哈哈,开个玩笑

    1. 有时候只是为了代码分块,比仅仅使用{}更直观些。
    2. 当你执行一段代码到一半,想跳过剩下的一半的时候,如果你正处于do while循环中,则能用break达到这个目的。
    3. 变形的goto,有些公司不让用goto
    4. 这样做也可以是兼容各种编译器。
    5. 为了展开的时候不会出错。如果直接放在花括号里会出错的

    这篇文章很详细哦

    评论 赞赏 2017-12-25
      wowh
      • 312

      do while(0) 还有个用的地方是在宏定义#define里

      不加大括号的代码

      #include <stdio.h>
      
      #define foo(x) int a = x;int b = x;
      
      int main()
      {
          int i = 0;
          if (i == 0)
              //无法编译,缺少大括号
              foo(2);
          else
              i = 1;
          return 0;
      }
      

      加了大括号的代码

      #include <stdio.h>
      
      //加上大括号
      #define foo(x) {int a = x;int b = x;}
      
      int main()
      {
          int i = 0;
          if (i == 0)
              //无法编译,后面多了个;号,得把;去了才能编译的过去,和C的语法不怎么协调
              foo(2);
          else
              i = 1;
          return 0;
      }
      

      do while(0)的代码

      #include <stdio.h>
      
      #define foo(x) do {int a = x;int b = x;} while(0)
      
      int main()
      {
          int i = 0;
          if (i == 0)
              //这下舒服了 xD
              foo(2);
          else
              i = 1;
      }
      
      评论 赞赏 2014-07-17
        henix
        • 1.3k

        块级作用域。避免 {} 块里面的变量名扩散到上层作用域中。好处是减少外层作用域中需要记忆的名字的数量,减少误用这些变量的可能性。

        具体来说,这段代码中 pImage 就被限制在只能在这个块中使用,出了这个块就不能用了,避免程序员误用,也避免名字冲突。

        在 C++ / Java 等支持块级作用域的语言中常见。gcc 还支持只写大括号:

        {
            int x = 0;
            // do something
        }
        // can't use x here
        {
            int x = 1; // another x
            // do something
        }
        // can't use x here
        
        评论 赞赏 2014-07-17

          另外一种作用是这样的使用goto来统一错误处理,如:

          bool foo()
          {
              int a, b, c;
              bool ok;
              ok = bar1(&a);
              if (!ok)
                  goto failed;
              ok = bar2(&a);
              if (!ok)
                  goto failed;
          failed:
              process_error();
              return false;
          exit:    
              return true;
          }
          

          如果配合do{}while(0)的话.会这样的

          bool foo()
          {
              int a, b, c;
              bool ok = true;
              do
              {  
                  ok = bar1(&a);
                  if(!ok)
                      break;
                  ok = bar2(&b);
                  if(!ok)
                      break;
              } while(0);
              if (!ok)
              {
                  process_error();
                  return false;
              }
              else
              {
                  return true;
              }
          }
          
          评论 赞赏 2014-07-17

            在宏里常用do-while, 比如

            #define SAFE_FREE(p) do {free(p);p=NULL;} while(0)
            

            在代码里调用这个宏:

            SAFE_FREE(ptr);
            

            用do-while, 上面的宏调用可以看起来像"函数调用", 句尾可以有分号
            因为do{} while(0); 最后可以带分号, 并且利用大括号把语句括起来;

            加入不用do-while, 上面的宏就写成:

            define SAFE_FREE(p)   free(p);p=NULL;
            

            调用的时候一般人会这么用:

            if(条件)
             SAFE_FREE(p); // 展开后, p=NULL就不在if控制内了
            
            评论 赞赏 2014-07-22
              撰写回答

              登录后参与交流、获取后续更新提醒