• do while(0)的作用以及原因


    在C++中,do...while 通常是用来做循环用的,然而我们做循环操作可能用for和while要多一些。经常看到一些开源代码会出现do...while(0)这样的代码,这样的代码看上去肯定不是用来做循环的,那为什么要这样用呢?

    实际上do...while(0)的作用远大于美化代码,现总结起来主要有以下几个作用:

     辅助定义复杂的宏,避免引用的时候出错,提高代码健壮性

    假设你需要定义一个这样的宏:

    1. #define DOSOMETHING()\
    2. func1();\
    3. func2();

    这个宏的本意是,当调用DOSOMETHING()时,函数func1()和func2()都会被调用。但是如果你在调用的时候这么写:

    1. if(a>0)
    2. DOSOMETHING();

    因为宏在预处理的时候会直接被展开,你实际上写的代码是这个样子的:

    1. if(a>0)
    2. func1();
    3. func2();

    这就出现了问题,因为无论a是否大于0,func2()都会被执行,导致程序出错。

    那么仅仅使用{}将func1()和func2()包起来行么?

    我们在写代码的时候都习惯在语句右面加上分号,如果在宏中使用{},代码里就相当于这样写了:“{...};”,假如有以下代码:

    1. #define DOSOMETHING(){\
    2. func1();\
    3. func2();}
    4. ...
    5. if(a>0)
    6. DOSOMETHING();
    7. else
    8. ...
    9. ...

    展开后就是这个样子:

    1. if(a>0)
    2. {
    3. func1();
    4. func2();
    5. };
    6. else
    7. ...

    这样是不会编译通过。所以,很多人才采用了do{...}while(0);

    1. #define DOSOMETHING() \
    2. do{ \
    3. func1();\
    4. func2();\
    5. }while(0)\
    6. ...
    7. if(a>0)
    8. DOSOMETHING();
    9. else
    10. ...
    11. ...

     消除分支语句或者goto语句,提高代码的易读性

    如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出函数,当然,退出前先释放资源,我们的代码可能是这样:

    1. bool Execute()
    2. {
    3. // 分配资源
    4. int *p = new int;
    5. bool bOk(true);
    6. // 执行并进行错误处理
    7. bOk = func1();
    8. if(!bOk)
    9. {
    10. delete p;
    11. p = NULL;
    12. return false;
    13. }
    14. bOk = func2();
    15. if(!bOk)
    16. {
    17. delete p;
    18. p = NULL;
    19. return false;
    20. }
    21. bOk = func3();
    22. if(!bOk)
    23. {
    24. delete p;
    25. p = NULL;
    26. return false;
    27. }
    28. // ..........
    29. // 执行成功,释放资源并返回
    30. delete p;
    31. p = NULL;
    32. return true;
    33. }

    这里一个最大的问题就是代码的冗余,而且我每增加一个操作,就需要做相应的错误处理,非常不灵活。于是我们想到了goto:

    1. bool Execute()
    2. {
    3. // 分配资源
    4. int *p = new int;
    5. bool bOk(true);
    6. // 执行并进行错误处理
    7. bOk = func1();
    8. if(!bOk) goto errorhandle;
    9. bOk = func2();
    10. if(!bOk) goto errorhandle;
    11. bOk = func3();
    12. if(!bOk) goto errorhandle;
    13. // ..........
    14. // 执行成功,释放资源并返回
    15. delete p;
    16. p = NULL;
    17. return true;
    18. errorhandle:
    19. delete p;
    20. p = NULL;
    21. return false;
    22. }

    代码冗余是消除了,但是我们引入了C++中身份比较微妙的goto语句,虽然正确的使用goto可以大大提高程序的灵活性与简洁性,但太灵活的东西往往是很危险的,它会让我们的程序捉摸不定,那么怎么才能避免使用goto语句,又能消除代码冗余呢,请看do...while(0)循环:

    1. bool Execute()
    2. {
    3. // 分配资源
    4. int *p = new int;
    5. bool bOk(true);
    6. do
    7. {
    8. // 执行并进行错误处理
    9. bOk = func1();
    10. if(!bOk) break;
    11. bOk = func2();
    12. if(!bOk) break;
    13. bOk = func3();
    14. if(!bOk) break;
    15. // ..........
    16. }while(0);
    17. // 释放资源
    18. delete p;
    19. p = NULL;
    20. return bOk;
    21. }

     使用代码块,代码块内定义变量,不用考虑变量重复问题

    当你的功能很复杂,变量很多你又不愿意增加一个函数的时候,使用do{}while(0);,将你的代码写在里面,里面可以定义变量而不用考虑变量名会同函数之前或者之后的重复。

  • 相关阅读:
    Multisim14.0仿真(十)同相放大器
    CSDN每日一练 |『相似三角形』『 运输石油』『鬼画符门之宗门大比』2023-09-13
    MATLAB算术运算符、关系运算符、逻辑运算符、按位集合运算符
    2022杭电多校八 1005-Ironforge(二分+区间暴力)
    Auracast 广播音频知识点
    【英语】常见连音规则
    使用Tomcat搭建一个Servlet项目
    SSM+基于java的企业任务流程管理系统开发 毕业设计-附源码221533
    机器学习模型5——贝叶斯分类器
    引爆记忆广告语盘点
  • 原文地址:https://blog.csdn.net/keep_contact/article/details/127838298