do{}while(0)的用法

2023-10-29

这几天在看代码的时候遇到了一个好像很神奇的用法:do{ … }while(0)。

do{ … }while(1)我能理解,就是一直循环,然后在循环体内设置跳出条件,或者干脆就不跳出。
那do{ … }while(0)是干嘛的呢?在内部也改变不了循环条件,然后执行一次就结束,那不就是没循环嘛?

赶紧查了一下,原来,这种用法主要是针对宏定义使用的。

这里我们来看一下如下代码:

#define INCREASE_TWO_VARIABLE(a, b)  a++;\
    b++;

我们定义了一个宏,其中包含了两条语句。看上去好像没什么问题。岁月静好,风平浪静。

但是,再考虑如下情景:

if(some_condition)
    INCREASE_TWO_VARIABLE(x, y); //请记住这个分号
else
    do_something;

嗯???好像哪里不对??我们把宏定义拆开:

if(some_condition)
    x++;
    y++;; //这里两个分号一个是宏定义内部的,一个是宏定义外部的。但是此时这里并不会报错,两个分号是可行的
else    //报错,没有对应的if语句
    do_something;

哎,这里就出现问题了,如果if后面不加大括号,那么只能跟一个语句,其他语句将被视为条件体之外的语句。那么此时,不仅y++一定会被执行,而且else没有对应的if语句,还会报错。(此时还好else会报错,不然编译通过,你却发现程序怎么都跑不对)

那咋办呢?不如我们用大括号把它括起来吧!于是我们修改了宏定义成这个亚子:

#define INCREASE_TWO_VARIABLE(a, b)  {\
    a++;\
    b++;\
}

然后刚才的情景就变成了:

if(some_condition)
{
    x++;
    y++;
};
else    //报错
    do_something;

嗯???不是?这个大括号后面的分号是怎么肥四!你在使用宏定义的时候后面就不能不加分号嘛!(请注意最开始的那个分号)

使用者:不,我不可以,我是强迫症!而且不加分号,VS会自动把else缩进4个空格,我还要手动删!

…………于是这个时候,你想起了传说中的do{ … }while(0)。于是你又把宏定义做了一个小小的修改:

#define INCREASE_TWO_VARIABLE(a, b)  do{\
    a++;\
    b++;\
}while(0)

于是刚刚的情景又变成了:

if(some_condition)
	do{
	    x++;
	    y++;
	}while(0);
else
    do_something;

于是编译又通过了,世界又恢复了和平。

此外,其实do{ … }while(0)还有另一种用法,虽然我依然觉得好像没什么卵用

if(condition1){
    do_something();
}
if(condition2){
    do_something();
}
if(condition3){
    do_something();
}
if(condition4){
    do_something();
}

这个时候do_something()会被各种执行,如果这一段代码非常复杂,那么看起来就会非常冗余。
虽然你可以使用宏定义将这些代码合在一起,也可以将condition合在一起变成一个if语句,但是你觉得使用宏定义不爽,合在一起又太乱,所以决定使用do{ … }while(0)。

do{
    if(condition1){
        break;
    }
    if(condition2){
        break;
    }
    if(condition3){
        break;
    }
    if(condition4){
        break;
    }
}while(0)
do_something();

所以总结来说:其实,do{ … }while(0)就是满足强迫症的,不接受反驳,over。
(其实这种用法应该是用来提高代码的一致性,是一种非常好的编程习惯,因为使用者并不会知道你这个宏的结尾该不该加分号)

(如有错漏,还望指摘)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

do{}while(0)的用法 的相关文章

  • 第七周7.1数组运算课堂学习记录 求素数的方法改进/优化集锦《程序设计入门——C语言》第七期 浙江大学 翁恺

    求素数基本方法及优化 1 基本方法求素数 从2到x 1测试是否可以整除 对于n来说要走n 1遍 n很大时相当于 n 遍 include
  • 【C++学习笔记(五十一)】之Qt中的信号和槽机制

    一 信号和槽机制 信号和槽机制分为信号和槽函数 用于处理事件 当某个事件发生时 比如说某个按钮被点击后 它就会发出一个信号 signal 如果有对象对这个信号感兴趣 那么它就会使用连接 connect 函数 将该信号与自己的一个槽函数 sl
  • 变量的声明和定义

    1 声明和定义的区别 变量声明规定了变量的类型和名字 而定义是在声明的基础上还开辟了存储空间 可能还会为变量初始化一个初始值 2 c 为什么要将声明和定义分开 c 支持分离式编译机制 允许将程序分割为若干个文件 每个文件可被独立编译 而为了
  • vector中reserve与resize区别

    vector中reserve与resize区别 一 基本概念 1 capacity 指容器在分配新的存储空间之前能存储的元素总数 2 size 指当前容器所存储的元素个数 二 reserve与resize 1 区别 1 reserve 只修
  • C++继承和多态

    C 继承和多态 继承 继承的本质 代码的复用 在基类中给所有派生类提供统一的虚函数接口 让派生类进行重写 然后就可以使用多态了 类和类的关系 a part of 一部分关系 继承 a kind of 一种的关系 继承引入了一些概念 基类 父
  • 「C++学习笔记」面向.Net Core的(C++)CLR类库非专业入门(+使用Opencv)

    关键词 C CLR Net Core Net Famework Opencv C 目录 什么是CLR类库 本文说明 创建Demo程序 调用dll 通过项目引用 通过dll文件引用 其他还没完全清楚的坑 有关C CLI这块的资料真的很少而且都
  • 【C++学习笔记(二十一)】之基类,子类的类型转换

    本文章由公号 开发小鸽 发布 欢迎关注 老规矩 妹妹镇楼 一 普通基类 子类的转换 子类是由继承于基类 通常子类的内容要比基类多一些 因此子类开辟的内存要比基类大一些 一 基类 gt 子类 向下类型转换 当我们要把基类强转为子类时 由于子类
  • C++ 学习笔记(17)tuple类型、bitset类型、随机数(引擎和分布)、IO库(操纵符、未格式化输入输出、随机访问)

    C 学习笔记 17 tuple类型 bitset类型 随机数 引擎和分布 IO库 操纵符 未格式化输入输出 随机访问 参考书籍 C Primer 5th 17 1 tuple 类型 17 1 1 定义和初始化tuple tuple 的构造函
  • C++构造函数简单实现电梯控制程序

    对于电梯 属性之一就是位置 所以要实现这一程序 要设置电梯的初始位置和按下电梯按钮改变的电梯的位置 代码如下 include
  • 03C++核心编程——黑马程序员

    C 核心编程 本阶段主要针对C 面向对象编程技术做详细讲解 探讨C 中的核心和精髓 1 内存分区模型 C 程序在执行时 将内存大方向划分为4个区域 代码区 存放函数体的二进制代码 由操作系统进行管理的 全局区 存放全局变量和静态变量以及常量
  • ubuntu-1804 配置 opevcv-4.0记录

    1 opencv安装包下载及解压 镜像地址 注意opencv contrib版本一致 下载zip压缩包 unzip opencv 4 0 0 zip unzip opencv contrib 4 0 0 解压后可以将版本号去掉 路径看起来好
  • C++进阶篇5:字符串查找

    在STL中 字符串查找可以实现多种功能 例如 搜索单个字符 搜索子串 实现前向搜索 后向搜索 分别实现搜索第一个和最后一个满足条件的字符 或子串 要明确的一点是 所有查找find 函数的返回值均是size type类型 即无符号整数类型 该
  • C++对象调用优化

    C 对象调用优化 临时对象拷贝构造新对象 临时对象就不会产生 常见的对象调用过程 c 编译器对于对象构造的优化 用临时对象拷贝新对象的时候 临时对象就不产生了 直接构造新对象就可以了 include
  • C++ stack容器-50-栈容器基本概念和常用接口

    接着学习下一个容器 stack 栈容器 当然后面还要学习一个队列容器 两个有点相似一般一起对比和学习 本篇主要学习栈容器的基本概念和常用接口的基本使用 1 什么是stack stack是一种先进后出 First In Last Out FI
  • 模板特化

    上一篇 模板与重载 里 我遇见了想同时使用模板函数与非模板函数的情况 后来才知道 其实并不需要 当我想对某些特定的类型进行特殊操作时 只需要使用模板特化就可以 所谓特化 就是说对于模板函数 对于某些类型可能需要特殊处理 所以进行特殊化 可以
  • C#学习笔记--关于银行存取款的小实验

    C 面向对象程序设计 编程模拟实现个人银行的存款业务 要求 1 提供两种账户 活期存款账户CheckingCustom和定期存款账户FixedCustom 2 创建活期账户时 必须提供账户名和开户金额 而账号则根据存款分类自动生成 3 不论
  • 【C++学习笔记】三、C++的数据类型、存储以及基本运算

    本文记录了C 中的数据类型以及基本运算 这部分是典型的每次记每次忘类型 所以烙印在此 以便用时随时查阅 主要参考 http www runoob com cplusplus cpp data types html 1 C 中的数据类型 1
  • C++泛型编程

    C 泛型编程 1 泛型编程 1 1 模板 1 2 函数模板 1 2 1 语法 1 2 2 使用函数模板方式 1 2 3 普通函数和函数模板的区别 1 2 4 普通函数与函数模板的调用规则 1 2 5 模板的局限性 1 3 类模板 1 3 1
  • C++类的构造函数

    构造函数 构造函数的概念 我们有一个Date类 class Date public void Init int year int month int day year year month month day day void Print
  • C#8.0本质论第十六章--使用查询表达式的LINQ

    C 8 0本质论第十六章 使用查询表达式的LINQ 像SQL这样的专业查询语言虽然容易阅读和理解 但又缺乏C 语言的完整功能 这正是C 语言设计者在C 3 0中添加 查询表达式 语法的原因 本章大部分都类似于SQL 一般不会使用到 在用到的

随机推荐

  • Elasticsearch实战(五)---高级搜索 Match/Match_phrase/Term/Must/should 组合使用

    Elasticsearch实战 Match Match phrase term filter 及Must should 组合并列使用 文章目录 Elasticsearch实战 Match Match phrase term filter 及
  • 2021-02-04

    问题描述 小明要做一个跑步训练 初始时 小明充满体力 体力值计为 10000 如果小明跑步 每分钟损耗 600 的体力 如果小明休息 每分钟增加 300 的体力 体力的损耗和增加都是均匀变化的 小明打算跑一分钟 休息一分钟 再跑一分钟 再休
  • JavaScript数组筛选的两种方法

    筛选数组的方法有两种 先简单说一下筛选数组主要是按照要求筛选数组里面的值 假设日常开发需要用到筛选数组里面大于十的值并放入到一个新的数组里面 这个时候我们就应该想到需要建一个新的数组并且还要把符合条件的值放入到新的数组里面下面我们先来看一下
  • End-to-End Semi-Supervised Object Detection with Soft Teacher 解读

    端到端的半监督目标检测 论文 https arxiv org pdf 2106 09018v3 pdf 代码地址 https github com microsoft SoftTeacher 整体框架 student model 的训练 标
  • JAVA年度安全 第三周 SESSION COOKIE SECURE 标识

    http www jtmelton com 2012 01 17 year of security for java week 3 session cookie secure flag What is it and why do I car
  • MySQL 数据库(DBMS)安装教程图文详解

    一 下载 在MySQL的官网上提供了两种安装方式 第一种是在线联网安装 第二种是本地安装 第一种必须联网安装 当安装时必须能够访问网络 第二种 离线安装即可 区别 第一种 在线联网安装 msi 会有图形界面向导方式安装 优点是可以比较清晰地
  • 分布式系统详解--框架(Hadoop-Ssh免密登陆配置)

    分布式系统详解 框架 Hadoop Ssh免密登陆配置 配置Ssh非常简单 其实就是为了避免将来集群机器变得很多导致操作本机 后者操作其它服务器输入密码的次数太多而浪费了太多的时间 在这儿我们配置了这个Ssh免登录将会节省一大部分时间 我们
  • Java-StringBuffer 和StringBuilder

    Java StringBuffer 和StringBuilder 1 StringBuffer StringBuilder中的常用方法 增 append xxx 删 delete int start int end 改 setCharAt
  • 用SQL语句从AD中读取用户相关属性 从AD中读取用户的相关属性

    参考原文链接 http www myexception cn sql server 1011477 html EXEC sp addlinkedserver ADSI Active Directory Services 2 5 ADSDSO
  • 从隔离中崛起:我重新梳理的‘大厂面试指南’助你一战成就职业巅峰

    在这个独特的时期 求职者们面临着前所未有的挑战 而我希望通过这份重新梳理的 大厂面试指南 能够为他们提供有力的支持和指导 我深知 面试是一个关键的环节 能否在众多竞争者中脱颖而出 决定着求职者能否顺利进入理想的大厂 现在 V2 0版的 大厂
  • 解决Error: Cannot find module 'node-sass'问题

    今天在运行angular前端的时候出现了以下的问题 解决办法 1 在项目目录cmd下运行 npm install g cnpm registry https registry npm taobao org 2 下载成功后再运行 cnpm i
  • Node.js在数据库进行多条件模糊查询的sql技巧

    实现简单的前台输入框查询筛选出内容包含的数据 使用ajax请求后台 后台拦截后再交给逻辑处理层 controller 再在dao层进行sql语句的查询并返回数据给逻辑层 blog search function req resp let s
  • 【多线程】ThreadPoolExecutor 类的使用详解

    ThreadPoolExecutor 构造方法 ThreadPoolExecutor共4个构造方法 咱们直接看参数最多的7个参数分别代表 public ThreadPoolExecutor 线程池核心线程数 int corePoolSize
  • 蓝桥云课——数字三角形 Python(动态规划)

    由于本人还在复习考研 留给蓝桥杯的时间不会太多 能不能拿奖还另说 听天由命吧 题目地址 数字三角形 一道比较简单的动态规划题目 比较适合新手学习 从动态规划三部曲开始走 1 先确认dp方程含义 在这我们采用二维数组 每个数组用来储存最大的值
  • Typora文本颜色设置

    Typora文本颜色设置 前言 方法一 使用markdown语法的内联公式 设置颜色 文本颜色设置公式 常用的颜色公式代码表 效果预览 方法二 使用html代码 设置颜色 文本颜色设置公式 颜色代码 方法三 借助第三方软件AutoHotKe
  • 数据库之SqlSessionTemplate源码解析

    前言 在普遍的JAVA WEB项目的实际业务处理中 最终都是通过SqlSessionTemplate执行数据库的CURD操作 本文结合mybatis源码 对SqlSessionTemplate进行详细的介绍 SqlSessionTempla
  • 【微信小程序】微信小程序怎么让tabbar右上角的红点动起来,闪烁红点。

    1 需要用到两个API分别是wx showTabBarRedDot 和wx hideTabBarRedDot wx showTabBarRedDot 显示 tabBar 某一项的右上角的红点 wx hideTabBarRedDot 隐藏 t
  • ERC20接口下USDT代币的深入解析

    ERC20代币合约规则简介 ERC20 是各个代币的标准接口 ERC20 代币仅仅是以太坊代币的子集 为了充分兼容 ERC20 开发者需要将一组特定的函数 接口 集成到他们的智能合约中 以便在高层面能够执行这些操作 获得代币总供应量 获得账
  • Hbase存储方式

    Hbase概念 HBase是一个分布式的 面向列的数据库它介于nosql和RDBMS之间 仅能通过主键 row key 和主键的range来检索数据 仅支持单行事务 可通过hive支持来实现多表join等复杂操作 主要用来存储非结构化和半结
  • do{}while(0)的用法

    这几天在看代码的时候遇到了一个好像很神奇的用法 do while 0 do while 1 我能理解 就是一直循环 然后在循环体内设置跳出条件 或者干脆就不跳出 那do while 0 是干嘛的呢 在内部也改变不了循环条件 然后执行一次就结