首页 > 其他分享 >你想知道的do{...}while(0)的作用,都在这里了

你想知道的do{...}while(0)的作用,都在这里了

时间:2023-02-21 22:33:13浏览次数:30  
标签:语句 do ... while funB FUN

 0、引言        

我们在嵌入式开发的过程中,经常可以碰到在一些宏定义或者是代码段中使用了do {...} while(0)的语句,从语义上理解,do {...} while(0)内的逻辑就只执行一次,并没有循环执行,粗略看来,似乎画蛇添足了,那么为什么还需要在只执行一次的逻辑外面加上一层do {...} while(0)语句呢?实际上,在这些逻辑中使用do {...} while(0)的作用远大于美化你的代码,下面就来看看实际的使用场景。


1、用于定义一个作用域,避免替换的时候出错

我们都知道,在程序中如果一些常量参数或者代码语句反复出现,就可以使用宏定义来替代。预处理阶段,对程序中所有出现的“宏名”,预处理器都会用宏定义中的字符串替代,这称为“宏替换”或“宏展开”。

这样做可提高程序的通用性和易读性,减少不一致性,一个较好的宏名可以更好的让读者理解常量参数的含义;同时程序易于修改,我们仅需要改变一个宏定义,就可以改变整个程序中出现的所有该常量或者语句。

但是有时可能程序代码段中,出现多条语句重复连续的使用,这样我们就可以尝试使用一个复杂的宏来替换。你有可能会这样定义:

#define REPLACE_FUN() funA(); funB()

本意是在程序中当出现funA()和funB()多条语句连续使用时,使用REPLACE_FUN()来替换。

if(判断条件)
REPLACE_FUN();

但是实际上在预处理的时候,宏展开替换后变成了:

if(判断条件)
funA();
funB(); //此处funB()一定会执行,造成逻辑错误

可以看出,funB()不会按照判断条件才去执行。而是变成了一条独立的语句,而如果在宏中使用括号:

#define REPLACE_FUN() {funA(); funB();}

我们一般的代码习惯都会在语句的末尾加上分号,因此也会出错:

if(判断条件)
REPLACE_FUN();
//宏展开后为:
if(判断条件)
{
funA();
funB();
}; //此处替换后多一个分号;导致编译报错

因此,针对这种多条重复语句的连续使用,如果想用宏替换实现这个作用域的功能,就可以考虑使用do {...} while(0)语句:

define REPLACE_FUN() \
do{ \
funA();\
funB();\
}while(0)\
//宏展开前为:
if(判断条件)
REPLACE_FUN();
//宏展开后为:
if(判断条件)
do{
funA();
funB();
}while(0); //根据判断条件,正确执行了一次逻辑

2、避免goto语句的使用

goto语句也称为无条件转移语句,使用后可以从多重循环或者多个判断中直接跳出。对于如下例子:

void fun(int a)
{
if(1 == a)
{
...//todo
goto exit;
}
if(2 == a)
{
...//todo
goto exit;
}
exit:
...//todo
printf("a is error"\n);
}

但是为了程序结构的清晰,还是要尽量限制goto语句的使用,我们可以使用do {...} while(0)结构配合break跳出单层的循环的方法来替代这种goto的用法。

int fun(int a)
{
do{
if(1 == a)
{
...//todo
break;
}
if(2 == a)
{
...//todo
break;
}
}while(0);
...//todo
printf("a is error"\n);
}

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

当某个函数程序功能较为复杂,在该函数的代码段中如果不再单独定义一个函数实现部分逻辑,可以使用do {...} while(0)作为一个代码块,将想要实现的逻辑放在do {...} while(0)中,同时在该在do {...} while(0)代码块中定义的变量,可以不用考虑和函数之前或者之后的变量名重复冲突的问题。但是为了代码的易读性,还是尽量声明不同的变量名。

int a;
char b;
int func()
{
int a = 3;
char b = 5;
do{
int a;
char b;
......//todo
}while(0);
}

4、避免空宏的警告

有的时候,程序为了不同的平台移植或者不同架构的限制,很多时候会先定义空宏,后续再根据实际的需要看是否定义具体内容。但是在编译的时候,这些空宏可能会给出warning,为了避免这样的warning,我们可以使用do{...}while(0)来定义空宏,这种情况不太常见,因为有很多编译器已经支持空宏。

//空宏
#define EMPTY_FUN
//增加do{...}while(0)来定义空宏
#define EMPTY_FUN do{}while(0) //避免了可能的编译warning

↓↓↓更多技术内容和书籍资料获取,入群技术交流敬请关注“明解嵌入式”↓↓↓

你想知道的do{...}while(0)的作用,都在这里了_算法

标签:语句,do,...,while,funB,FUN
From: https://blog.51cto.com/Sharemaker/6077093

相关文章

  • float和double类型在计算机中是怎么储存的
    我们先看一个代码。#include<stdio.h>intmain(){intn=9;float*pfloat=(float*)&n;printf("n的值为:%d",n);printf("*pfloat的值为%f\n",*pfloat);*pfloa......
  • J'aimerais que ces doux moments durent pour toujours
    Dimanche19février2023Ceciestuneescapadedeweek-end,notredernierrassemblementfamilialenEurope.J'aimeraisquecesdouxmomentsdurentpluslongte......
  • docker学习
    1.背景打算装虚拟机,嫌麻烦,想到docker也可以实现,所以在本地部署docker2.docker和虚拟机的区别linux环境安装docker和制作镜像win11环境安装docker和制作镜像......
  • 【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeave
    问题描述在AzureAppServiceforWindows的环境中,部署.NET应用,其中使用了 SAPNetWeaverRFC函数(需要加载sapnwrfc.dll)。详细的错误为:“System.DllNotFoundExcepti......
  • windows下编译pdfium
    当前流程截至2023/2/20有效1、提前安装好工具链VS2017+SDK Win10SDK10.0.20348 +Gitforwindows+tortoisegit+代理2、下载depot_tools命令行中设置环境变......
  • windows下编译live555
    最近需要编译Live555库,在windows下编译完成后,在此记录。笔者的电脑系统是Windows10。首先在live555官网下载源码,下载链接是:LIVE555.COM。在该链接下,还有一个......
  • Windows系统配置ODBC访问KingbaseES数据库
    Windows系统使用KingbaseESODBC驱动访问KingaseES数据库及常见问题解决。一、获取KingbaseES数据库ODBC驱动:在官网下载KingbaseES数据库安装包,选择对应平台的安装包。......
  • linux基本功系列之sudo命令实战
    #前言......
  • 一次docker-compose建立镜像但无法找到
    环境:zabbix官网提供的docker-compoes一开始以为是ports没有配置,但配置后dockerps-a所显示的还是为空,在重新翻找过后,查到是zabbix的compose建立了两个brige,在zabbix的配......
  • dokuwiki支持pdf粘帖
    ​ ueditor粘贴不能粘贴word中的图片是一个很头疼的问题,在我们的业务场景中客户要求必须使用ueditor并且支持word的图片粘贴,因为这个需求头疼了半个月,因为前端方面因为安......