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

简介: do while(0)的作用以及原因

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

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

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

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

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

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

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

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

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

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

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

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

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

展开后就是这个样子:

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

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

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

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

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

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

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

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

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

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

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

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

相关文章
|
JavaScript
Vue引入字节跳动图标库
Vue引入字节跳动图标库
411 0
Vue引入字节跳动图标库
|
Java
CompletableFuture在异常处理方面的一些常见问题和解决方案,建议牢记!
CompletableFuture在异常处理方面的一些常见问题和解决方案,建议牢记!
799 0
CompletableFuture在异常处理方面的一些常见问题和解决方案,建议牢记!
|
SQL 弹性计算 开发框架
【ECS生长万物之开源】手动搭建Drupal网站
Drupal是使用PHP语言编写的开源内容管理框架(CMF),它由内容管理系统(CMS)和PHP开发框架(Framework)共同构成。它用于构造提供多种功能和服务的动态网站,能支持从个人博客到大型社区等各种不同应用的网站项目。本教程适用于熟悉Linux系统,刚开始使用阿里云进行建站的用户。
|
11月前
|
SQL 存储 关系型数据库
如何巧用索引优化SQL语句性能?
本文从索引角度探讨了如何优化MySQL中的SQL语句性能。首先介绍了如何通过查看执行时间和执行计划定位慢SQL,并详细解析了EXPLAIN命令的各个字段含义。接着讲解了索引优化的关键点,包括聚簇索引、索引覆盖、联合索引及最左前缀原则等。最后,通过具体示例展示了索引如何提升查询速度,并提供了三层B+树的存储容量计算方法。通过这些技巧,可以帮助开发者有效提升数据库查询效率。
996 2
|
7月前
|
供应链 搜索推荐 API
亚马逊商品列表数据接口(亚马逊 API 系列)
亚马逊的商品列表数据接口为电商从业者、数据分析人员和开发者提供了宝贵的市场洞察。通过该接口,用户可以批量获取商品的关键信息,包括基本信息、价格、销售排名和库存状态等,助力市场分析、竞品研究和商品推荐。开发者需在亚马逊开发者中心注册并申请API权限,使用安全凭证进行认证,支持HTTP/HTTPS协议的GET和POST请求。Python示例展示了如何调用接口获取商品列表,并解析响应数据。应用场景涵盖市场趋势分析、竞品对比、个性化推荐及库存管理,帮助商家优化策略,提升竞争力。
359 13
|
9月前
|
存储 NoSQL MongoDB
Redis在中国火爆,为何MongoDB更受欢迎国外?
本文介绍了Redis和MongoDB的基本概念及其在GitHub Star、DB-Engines Ranking和Google Trends中的数据对比。Redis是一个基于内存的键值对存储数据库,适合快速读写场景;MongoDB则是面向文档的数据库,支持大规模数据存储和复杂查询。全球范围内,MongoDB的搜索热度高于Redis,但在中国市场,Redis更受欢迎,因其高性能和低延迟特性满足了中国互联网公司对高并发的需求。总结部分分析了两者的特点及适用场景,并结合中美两国的行业背景解释了其受欢迎程度的不同原因。
276 1
|
11月前
|
机器学习/深度学习 人工智能 测试技术
VisionTS:基于时间序列的图形构建高性能时间序列预测模型,利用图像信息进行时间序列预测
构建预训练时间序列模型的主要挑战在于获取高质量、多样化的时间序列数据。目前有两种方法:迁移学习LLM(如GPT-4或Llama)和从零训练。尽管迁移学习可行,但效果有限;从零训练则依赖大量数据,如MOIRAI、TimesFM和TTM等模型所示。为解决这一难题,研究人员提出利用图像数据进行时间序列预测。
705 11
VisionTS:基于时间序列的图形构建高性能时间序列预测模型,利用图像信息进行时间序列预测
|
12月前
|
机器学习/深度学习 数据采集 网络安全
使用Python实现深度学习模型:智能网络安全威胁检测
使用Python实现深度学习模型:智能网络安全威胁检测
628 6
|
监控 安全 API
5 款漏洞扫描工具:实用、强力、全面(含开源)(二)
5 款漏洞扫描工具:实用、强力、全面(含开源)
1252 0
5 款漏洞扫描工具:实用、强力、全面(含开源)(二)
|
11月前
|
安全 Java 测试技术
ToB项目身份认证AD集成(二):快速搞定window server 2003部署AD域服务并支持ssl
本文详细介绍了如何搭建本地AD域控测试环境,包括安装AD域服务、测试LDAP接口及配置LDAPS的过程。通过运行自签名证书生成脚本和手动部署证书,实现安全的SSL连接,适用于ToB项目的身份认证集成。文中还提供了相关系列文章链接,便于读者深入了解AD和LDAP的基础知识。
474 0