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

0、引言        

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


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

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

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

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

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

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

1 if(判断条件)
2     REPLACE_FUN();

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

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

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

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

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

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

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

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

 1 define REPLACE_FUN() \
 2         do{ \
 3             funA();\
 4             funB();\
 5           }while(0)\
 6 //宏展开前为:         
 7 if(判断条件)
 8     REPLACE_FUN();
 9 //宏展开后为:
10 if(判断条件)
11      do{
12           funA();
13           funB();
14      }while(0);    //根据判断条件,正确执行了一次逻辑

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


2、避免goto语句的使用

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

 1 void fun(int a)
 2 {
 3    if(1 == a)
 4    {
 5        ...//todo
 6        goto exit;
 7    }  
 8    if(2 == a)
 9    {
10      ...//todo
11      goto exit;
12    }
13 exit:
14    ...//todo
15    printf("a is error"\n);
16 }

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

 1 int fun(int a)
 2 {
 3    do{
 4        if(1 == a)
 5        {
 6          ...//todo
 7          break;
 8        }  
 9        if(2 == a)
10        {
11          ...//todo
12          break;
13        }
14    }while(0);
15    ...//todo
16    printf("a is error"\n);
17 }

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

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

 1 int a;
 2 char b;
 3 int func()
 4 {
 5     int a = 3;
 6     char b = 5;
 7     do{
 8         int a;
 9         char b;
10         ......//todo
11     }while(0);    
12 }

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


4、避免空宏的警告

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

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

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

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

原文链接:https://www.cnblogs.com/Sharemaker/p/17142670.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:你想知道的do{…}while(0)的作用,都在这里了 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • win7无法开机怎么办?解决开机报错代码C0000034的方法

    下面是详细的攻略: 一、背景介绍 Win7无法开机的情况,一般有两种错误代码:C0000034和C000021A。本文将重点介绍如何解决C0000034的问题。 二、问题分析 C0000034是Windows系统文件错误代码之一,意味着系统文件缺失或损坏,导致电脑无法正常启动。一般来讲,主要原因可能是: 1.蓝屏或死机后,Windows系统文件丢失或损坏 2…

    C 2023年5月23日
    00
  • C++定时器Timer在项目中的使用方法

    下面是“C++定时器Timer在项目中的使用方法”的攻略。 1. Timer类和定时器的原理 首先,要使用C++定时器,我们需要了解Timer类以及定时器的原理。Timer类实现了简单的定时器功能。它内部使用了C++11的库,通过高精度计时来实现定时器的功能。定时器的原理是:在一定时间间隔之后执行一个任务,而这个任务可以是一个函数,一个类的成员函数,或者一个…

    C 2023年5月23日
    00
  • vue中ts无法识别引入的vue文件,提示找不到xxx.vue模块的解决

    在Vue项目中使用TypeScript,当我们通过import导入.vue文件时,TS可能会抱怨找不到模块。这是因为TypeScript没有为.vue文件定义类型声明。为了解决这个问题,需要安装”vue-class-component”和”vue-property-decorator”两个库,并对tsconfig.json文件进行一些配置。 以下是具体步骤:…

    C 2023年5月23日
    00
  • 真三国无双7:猛将传关银屏C技怎么追加攻击? 关银屏C技追加攻击方法介绍

    OK,让我为您详细讲解“真三国无双7:猛将传关银屏C技怎么追加攻击?关银屏C技追加攻击方法介绍”的完整攻略。 猛将传关银屏C技的追加攻击 首先,我们需要知道什么是“C技追加攻击”。在真三国无双7中,每个武将都有自己的C技能,在使用C技能的时候,可以通过按下Attack按钮来进行追加攻击,有些武将的追加攻击可以造成更高的伤害,关银屏就是其中之一。 关银屏的C技…

    C 2023年5月23日
    00
  • 腾讯面试算法题之编码问题案例分析

    下面我将详细讲解“腾讯面试算法题之编码问题案例分析”的完整攻略。 1. 算法题背景 腾讯面试中,有可能会涉及到编码问题。在计算机中,一个字符可以使用不同的编码方式进行存储和传递,如ASCII、UTF-8、GBK等。如果不注意编码问题,就有可能产生乱码或无法解析的情况。因此在面试中,掌握编码问题是非常重要的。 2. 编码问题解决方法 编码问题的解决方法主要有以…

    C 2023年5月23日
    00
  • C语言实现简易通讯录实例

    C语言实现简易通讯录实例 简介 本项目将使用C语言实现一个简易通讯录,可以添加联系人、删除联系人、修改联系人以及查看通讯录中所有联系人的信息。 环境 开发平台:Windows / Linux / MacOS 编译器:gcc 功能列表 添加联系人 删除联系人 修改联系人 查看通讯录中所有联系人的信息 数据结构 为了实现通讯录的功能,我们需要用到两种数据结构:联…

    C 2023年5月30日
    00
  • C语言实现Floyd算法

    C语言实现Floyd算法 什么是Floyd算法 Floyd算法是一种用于寻找给定的加权图中多源点之间最短路径的算法,也称为Floyd-Warshall算法。 其时间复杂度为O(N^3),适用于需要求解所有顶点对间最短路径的场景。 算法思路 Floyd算法的思路是利用动态规划的思想,通过逐步考虑添加中间顶点的方式来逐步求得顶点对间的最短路径。 也就是说,我们首…

    C 2023年5月22日
    00
  • C++11标准库bind函数应用教程

    C++11标准库bind函数应用教程 简介 bind函数是C++ 11标准库中提供的一个重要工具,它可以用来将函数绑定到参数上。bind函数可以将一个函数作为参数,将该函数的某些参数绑定到指定的值上,使得这些参数的值在调用函数时被固定,从而达到重复利用该函数的目的。 语法 template <class F, class… Args> /*返…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部