do{...}while(0)的意义和用法

简介:

linux内核和其他一些开源的代码中,经常会遇到这样的代码:

do{
 ...
}while(0)

这样的代码一看就不是一个循环,do..while表面上在这里一点意义都没有,那么为什么要这么用呢?

实际上,do{...}while(0)的作用远大于美化你的代码。查了些资料,总结起来这样写主要有以下几点好处:

1、辅助定义复杂的宏,避免引用的时候出错:

举例来说,假设你需要定义这样一个宏:

#define DOSOMETHING()\
               foo1();\
               foo2();

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

if(a>0)
    DOSOMETHING();

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

if(a>0)
    foo1(); foo2();

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

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

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

if(a>0)
{ foo1(); foo2(); };

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

#define DOSOMETHING() \
        do{ \
          foo1();\
          foo2();\
        }while(0)\
    
...
 
if(a>0) DOSOMETHING();   ...

这样,宏被展开后,才会保留初始的语义。GCC提供了Statement-Expressions用以替代do{...}while(0); 所以你也可以这样定义宏:

#define DOSOMETHING() ({\
        foo1(); \
        foo2(); \
})

http://www.spongeliu.com/ 
2、避免使用goto对程序流进行统一的控制:

有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,goto一直都是一个比较简便的方法:

int foo()
{
    somestruct* ptr = malloc(...);   dosomething...; if(error) { goto END; }   dosomething...; if(error) { goto END; } dosomething...;   END: free(ptr); return 0;   }

由于goto不符合软件工程的结构化,而且有可能使得代码难懂,所以很多人都不倡导使用,那这个时候就可以用do{}while(0)来进行统一的管理:

int foo()
{
 
    somestruct* ptr = malloc(...);   do{ dosomething...; if(error) { break; }   dosomething...; if(error) { break; } dosomething...; }while(0);   free(ptr); return 0;   }

这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。

 

3、避免空宏引起的warning

内核中由于不同架构的限制,很多时候会用到空宏,在编译的时候,空宏会给出warning,为了避免这样的warning,就可以使用do{}while(0)来定义空宏:

#define EMPTYMICRO do{}while(0)

 

4、定义一个单独的函数块来实现复杂的操作:

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



本文转自莫水千流博客园博客,原文链接:http://www.cnblogs.com/zhoug2020/p/6655172.html,如需转载请自行联系原作者

相关文章
|
存储 芯片 内存技术
Jlink使用技巧之读写SPI Flash存储芯片
Jlink使用技巧之读写SPI Flash存储芯片
2458 0
Jlink使用技巧之读写SPI Flash存储芯片
|
机器学习/深度学习 安全 Linux
Linux 主要应用领域的归纳
服务器领域 Linux在服务器领域的应用是其最为广泛和成熟的领域之一。由于其开源、稳定、高效和安全的特性,Linux成为许多企业服务器的首选操作系统。 Web服务器:Linux是Web服务器的理想选择,因为它支持Apache、Nginx等流行的Web服务器软件,这些软件在Linux上运行稳定且性能卓越。Linux服务器可以高效地处理大量并发请求,提供快速、可靠的Web服务。 数据库服务器:Linux也广泛用于数据库服务器,如MySQL、PostgreSQL和Oracle等数据库管理系统在Linux上运行良好。Linux的稳定性和安全性使得它成为存储和管理敏感数据的理想平台。 邮件服务器:Lin
712 5
|
网络协议 算法 安全
802.11帧结构与WiFi控制帧、管理帧、数据帧
【9月更文挑战第26天】该内容详细介绍了802.11帧结构,包括帧头、帧体和帧尾三部分,并分别阐述了各部分的功能和作用。此外,还介绍了WiFi控制帧、管理帧和数据帧的功能及类型,涵盖了RTS/CTS、ACK、信标帧、关联请求/响应帧、认证帧等内容,解释了它们在网络通信中的具体应用。
1969 3
|
JSON Java 网络架构
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
这篇文章介绍了如何使用Spring Boot整合REST方式来搭建和操作Elasticsearch服务。
441 4
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
|
前端开发 JavaScript Java
SpringCloudGateway网关服务实现文件上传功能
SpringCloudGateway网关服务实现文件上传功能
444 9
|
数据采集 存储 人工智能
《文档智能 & RAG让AI大模型更懂业务解决方案评测》
本文介绍了通过文档智能和RAG技术将业务文档整合到大语言模型(LLM)知识库中的实践原理,涵盖了理解情况、技术细节、部署体验、知识库优势及适用场景。重点讨论了文档解析、信息提取、语义理解等步骤,以及RAG技术在LLM中的应用。同时,提出了在技术细节、部署引导、知识库更新和性能优化等方面的改进建议,强调了该方案在企业内部知识管理、客户服务和业务流程自动化中的适用性,但也指出了在安全性、系统集成和性能稳定性方面的不足。
323 0
|
人工智能 安全 5G
|
NoSQL 编译器 Linux
CodeBlocks-20.03下载安装及中文教程
CodeBlocks-20.03下载安装及中文教程
4711 5
|
IDE NoSQL 编译器
Vscode搭建开发调试STM32/RISC-V环境IDE(最全面)
Vscode搭建开发调试STM32/RISC-V环境IDE(最全面)
|
安全
干货|最全PCB布线教程总结,14条PCB布线原则技巧,保姆级搞定PCB布线
干货|最全PCB布线教程总结,14条PCB布线原则技巧,保姆级搞定PCB布线
2737 0