do {...} while (0) 在宏定义中的作用

2023-05-16

http://www.cnblogs.com/lanxuezaipiao/p/3535674.html

如果你是一名C程序员,你肯定很熟悉宏,它们非常强大,如果正确使用可以让你的工作事半功倍。然而,如果你在定义宏时很随意没有认真检查,那么它们可能使你发狂,浪费N多时间。在很多的C程序中,你可能会看到许多看起来不是那么直接的较特殊的宏定义。下面就是一个例子:

1

2

#define __set_task_state(tsk, state_value)      \

    do { (tsk)->state = (state_value); } while (0)

在Linux内核和其它一些著名的C库中有许多使用do{...}while(0)的宏定义。这种宏的用途是什么?有什么好处?

Google的Robert Love(先前从事Linux内核开发)给我们解答如下:

do{...}while(0)在C中是唯一的构造程序,让你定义的宏总是以相同的方式工作,这样不管怎么使用宏(尤其在没有用大括号包围调用宏的语句),宏后面的分号也是相同的效果。

这句话听起来可能有些拗口,其实用一句话概括就是:使用do{...}while(0)构造后的宏定义不会受到大括号、分号等的影响,总是会按你期望的方式调用运行。

例如:

1

#define foo(x) bar(x); baz(x)

然后你可能这样调用:

1

foo(wolf);

这将被宏扩展为:

1

bar(wolf); baz(wolf);

这的确是我们期望的正确输出。下面看看如果我们这样调用:

1

2

if (!feral)

    foo(wolf);

那么扩展后可能就不是你所期望的结果。上面语句将扩展为:

1

2

3

if (!feral)

    bar(wolf);

baz(wolf);

显而易见,这是错误的,也是大家经常易犯的错误之一。

 

几乎在所有的情况下,期望写多语句宏来达到正确的结果是不可能的。你不能让宏像函数一样行为——在没有do/while(0)的情况下。

如果我们使用do{...}while(0)来重新定义宏,即:

1

#define foo(x) do { bar(x); baz(x); } while (0)

现在,该语句功能上等价于前者,do能确保大括号里的逻辑能被执行,而while(0)能确保该逻辑只被执行一次,即与没有循环时一样。

对于上面的if语句,将会被扩展为:

1

2

if (!feral)

    do { bar(wolf); baz(wolf); } while (0);

从语义上讲,它与下面的语句是等价的:

1

2

3

4

if (!feral) {

    bar(wolf);

    baz(wolf);

}

这里你可能感到迷惑不解了,为什么不用大括号直接把宏包围起来呢?为什么非得使用do/while(0)逻辑呢?

例如,我们用大括号来定义宏如下:

1

#define foo(x)  { bar(x); baz(x); }

这对于上面举的if语句的确能被正确扩展,但是如果我们有下面的语句调用呢:

1

2

3

4

if (!feral)

    foo(wolf);

else

    bin(wolf);

宏扩展后将变成:

1

2

3

4

5

6

if (!feral) {

    bar(wolf);

    baz(wolf);

};

else

    bin(wolf);

大家可以看出,这就有语法错误了

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

do {...} while (0) 在宏定义中的作用 的相关文章

  • arm-linux开发环境之(busybox-ls命令)终端显示颜色

    在开发板终端中输入ls命令后终端文件夹和文件显示颜色 linux主机 xff1a ubuntu 12 04 交叉编译器 xff1a gcc version 4 6 2 20110630 prerelease 开发板kernel xff1a
  • 活体识别5:论文笔记之FeatherNets

    说明 这篇文章是这次比赛的第三名 xff1a ChaLearn Face Anti spoofing Attack Detection Challenge 64 CVPR2019 xff0c 此次比赛项目是人脸防欺诈攻击检测 论文标题 xf
  • c++中使用dlopen加载动态库中带类参数的函数

    说明 我一直都知道dlopen的大概用法 但是dlopen毕竟是c语言的函数 xff0c 能否加载带c 43 43 类型传参的函数 xff0c 我有点不确定 今天有空验证了下 xff0c 是可以的 extern C 只影响了函数在动态库中的
  • 将pytorch的pth文件固化为pt文件

    说明 我参考了一个开源的人像语义分割项目mobile phone human matting xff0c 这个项目提供了预训练模型 xff0c 我想要将该模型固化 xff0c 然后转换格式后在嵌入式端使用 该项目保存模型的代码如下 xff1
  • ARM汇编1:如何在C语言中使用汇编

    如何在C语言中使用汇编语言 我最近对ARM的NEON编程有兴趣 xff0c 主要是为了想学习一些矩阵计算加速相关的知识 但是我又不想写纯粹的汇编语言 xff0c 我想在C语言中嵌入汇编来使用 经过检索学习 xff0c 我找到两种可行的方式
  • EEPROM和flash的区别

    之前对各种存储器一直不太清楚 xff0c 今天总结一下 存储器分为两大类 xff1a ram和rom ram就不讲了 xff0c 今天主要讨论rom rom最初不能编程 xff0c 出厂什么内容就永远什么内容 xff0c 不灵活 后来出现了
  • python中import cv2遇到的错误及安装方法

    从x86 64 43 ubuntu14 04 43 python3 5中import cv2 opencv3 3 遇到以下错误 xff1a ImportError libSM so 6 cannot open shared object f
  • 多目标跟踪-MOT16数据集格式介绍

    背景介绍 多目标跟踪的问题是这样的 xff1a 有一段视频 xff0c 视频是由 N 个 连续帧构成的 从第一帧到最后一帧 xff0c 里面有多个目标 xff0c 不断地有出有进 xff0c 不断地运动 我们的目的是对每个目标 xff0c
  • opencv-python的格式转换 RGB与BGR互转

    opencv读取图片的默认像素排列是BGR xff0c 和很多其他软件不一致 xff0c 需要转换 这里转一下国外博客的一个方法 xff0c 基于python语言 BGR to RGB OpenCV image to Matplotlib
  • np.maximum()函数详解——将数组中小于某值的数用0代替

    目标 xff1a 把数组中小于某个值的数都设为0 np max a axis 61 None out 61 None keepdims 61 False 求a中的最大值 np maximum xff1a a b out 61 自定义 a 与
  • python-opencv 使用LBP特征检测人脸

    概述 最近在做人脸检测相关功能 xff0c 目前注意到比较传统 xff08 非深度 xff09 人脸检测特征包括harr和LBP HOG用于行人检测更多些 xff0c opencv包括了这两种特征算法 xff0c 并且相对来说 xff0c
  • 机器视觉特征提取介绍:HOG、SIFT、SURF、ORB、LBP、HAAR

    一 概述 这里主要记录自己的一些感悟 xff0c 不是很系统 想要详细系统的理论 xff0c 请参考文末的 图像处理之特征提取 个人不是专业cv工程师 xff0c 很多细节没有深究 xff0c 描述可能不严谨 在总结物体检测算法之前先把基础
  • win7 wifi 无Internet访问权限或者有限的访问权限

    自己家的无线路由器 xff0c 手机和笔记本都使用正常 xff0c 但是一台新笔记本连上之后总是提示 有限的访问权限 xff0c 无法连公网 网上的很多办法都不管用 xff0c 什么设置静态IP或者重启路由 xff0c 基本都是瞎扯 好在一
  • springboot 本地调试没问题,打包运行报错原因

    1 如果引用了本地jar包或者so库 xff0c dll库等文件 xff0c 需要在打包的时候都加载进去 如下图 xff1a 本地正常 xff0c 打包的时候谨记 xff0c 需要打包进去 xff0c 怎么验证是否打包成功呢 xff1f 我
  • CMakeList学习笔记

    hello cpp为源文件 构建一个CMakeLists txt cmake minimum required VERSION 2 8 project hello add executable hello hello cpp 在目录中的bu
  • C语言--iota函数

    一 iota函数 xff1a 功能 把一个整数转换为字符串 eg include lt stdlib h gt include lt stdio h gt void main int number 61 43 char string 100
  • STM32F103ZET6和STM32F103C8T6编程不一样吗?

    我把C C 43 43 选项卡中 STM32F10X HD USE STDPERIPH DRIVER 修改为 STM32F10X MD USE STDPERIPH DRIVER 编译成功 谢谢O O 初始化的时候要调用SystemInit
  • STM32F103ZET6和STM32F103C8T6芯片的区别

    是这样的 xff0c 一个具体的STM32F103系列芯片的内存有多大 xff0c 你看一下芯片上的型号就行了 STM32F103XY 注意 xff0c XY是个代号 xff0c X是表示封装有多少个引脚 xff0c 比如 xff0c 如果
  • Keil(MDK-ARM)使用教程——在线调试

    Keil xff08 MDK ARM xff09 使用教程 xff08 三 xff09 在线调试 由于我是直接使用 xff08 打开现有的软件工程 xff09 xff0c 如果跟着需要下载上面演示参考的软件工程 才行 工程默认是使用硬件在线
  • ch340是什么芯片

    CH340 是一个USB 总线的转接芯片 xff0c 实现USB 转串口 USB 转IrDA 红外或者USB 转打印口 在串口方式下 xff0c CH340 提供常用的MODEM联络信号 xff0c 用于为计算机扩展异步串口 xff0c 或

随机推荐

  • Ubuntu16的详细安装教程

    有一点很重要要说一下 xff0c 每个人学习Linux的动机都不一样 xff0c 而这个动机会决定你对Linux的态度 xff0c 如果你仅仅是想尝鲜 xff0c 装个笔什么的 xff0c 不当作自己的职业方向去学习Linux的 劝这类人还
  • 是否能在keil中混合编译c和c++程序

    keil中支持混合编译C和C 43 43 程序 xff0c 因为其本质最终都是编译成汇编 xff0c 所以是可以同时操作的 在混合编译时 xff0c 需要注意以下几点 xff1a 1 C文件扩展名必须为 C xff0c C 43 43 文件
  • ds18b20工作原理和测温原理介绍

    DS18B20是美国DALLAS半导体公司继DS1820之后最新推出的一种改进型智能温度传感器 与传统的热敏电阻相比 xff0c 他能够直接读出被测温度并且可根据实际要求通过简单的编程实现9 xff5e 12位的数字值读数方式 可以分别在9
  • 如何将.hex文件转化为.c文件

    说明楼主太初级 xff0c 迷恋于C 1 C与HEX并不是一一映射的 xff0c 有可能N个人写的C xff0c 会出同一个HEX xff0c 你希望回成哪个人写的呢 xff1f 或许你可能说 xff1a 任意一个孝可以 xff0c 只要能
  • 嵌入式linux 和 用stm32进行的嵌入式开发 这两者之间有什么关联性吗?

    作者 xff1a 知乎用户 链接 xff1a https www zhihu com question 53880054 answer 164501004 来源 xff1a 知乎 著作权归作者所有 商业转载请联系作者获得授权 xff0c 非
  • #if 0 ... #endif的真实用途

    在过去都没有去理会 if 的作用 xff0c 今天突发奇想 xff0c 开启编译器试一试 很多人都知道 if 0 endfif的作用跟 的作用是一样的 xff0c 就是注释 xff0c 可是注释为什么不用注释符号 就行了么 xff1f go
  • .hex文件和.bin文件区别

    HEX文件和BIN文件是我们经常碰到的2种文件格式 因为自己也是新手 xff0c 所以一直对这两个文件懵懵懂懂 xff0c 不甚了解 xff0c 最近在做STM32单片机的IAP更新 xff0c 其中要考虑HEX文件和BIN文件 xff0c
  • EEPROM和flash的区别

    From https blog csdn net yuanlulu article details 6163106 EEPROM的全称是 电可擦除可编程只读存储器 xff0c 即Electrically Erasable Programma
  • 264 nal type

    NUAL HEAD 43 43 0 1 2 3 4 5 6 7 43 43 43 43 43 43 43 43 43 F NRI Type 43 43 F xff1d Forbidden zero bit 61 0 NRI 61 Nal r
  • SubClassWindow详解

    许多Windows程序员都是跳过SDK直接进行RAD开发工具 或VC xff0c 我想VC应不属于RAD 的学习 xff0c 有些人可能对子类化机制比较陌生 我们先看看什么是Windows的子类化 Windows给我们或是说给它自己定义了许
  • stl upper_bound函数实现

    写了一个upper bound的实现 其中递归使用二分法求解最上界 xff0c 虽然写的完全不像STL的风格 xff0c 但是练手还是可以的 view plaincopy to clipboardprint 01 include lt io
  • 云原生 - 2、Openstack架构

    云原生 2 Openstack架构 1 什么是Openstack2 Release3 核心架构4 官方入口5 核心组件6 相关文章导读 1 什么是Openstack OpenStack是一个开源的云计算管理平台项目 xff0c 由NASA
  • 关于TrackMouseEvent用法总结

    对于这个函数我也是最近想研究控件自绘才知道它真正怎么用 以前只是见到过 嗯 废话不多说 我先说下我的问题 如何响应鼠标离开某个窗体 控件 事件 先大概讲下步骤 然后再集中对 TrackMouseEvent 进行详解 为按钮添加以下几个函数
  • 关于CComboBox的自绘

    我想 如果大家学过一些控件的自绘的话 CComboBox算是很难的一种了 首先是它本身的复杂度 它由三个控件组成 CEdit CListBox CButton 我想但就CEdit来讲 就够你受得了 还要想想他们之间的消息传递 不禁让人无从下
  • 2011年总结

    又是一年年终时 亦是一年总结时 想想自己从去年写年终总结到现在 已经很久没有写过字了 时间过得真快 又是一年过去了 这一年也是我出来工作的第二年 这一年总体来说自己无论在技术还是心态方面有了很大的进步 记得刚出学校那会 啥都不知道 对于工作
  • 内部链接与外部链接

    在说内部连接与外部连接前 xff0c 先说明一些概念 1 声明 一个声明将一个名称引入一个作用域 在c 43 43 中 xff0c 在一个作用域中重复一个声明是合法的 以下都是声明 xff1a int foo int int 函数前置声明
  • partition/stable_partition详解

    Partition 将满足条件的元素向前移动 TEMPLATE FUNCTION partition template lt class BidIt class Pr gt inline BidIt Partition BidIt Firs
  • jsoncpp解析拼装数组

    int main 数组创建与分析 例子一 string strValue 61 34 34 ldh 34 34 001 34 34 gfc 34 34 002 34 34 yyj 34 34 003 34 34 andy 34 34 005
  • 查看静态库(.lib)和动态库(.dll)的导出函数的信息

    一般情况下 xff0c 我们需要查看一个DLL或EXE中的包含的函数或是依赖的函数之类的信息 xff0c 可以使用VS自带的工具dumpbin xff1b 可以直接在命令行下输入dumpbin就可以查看他的使用说明 xff0c 如果未显示
  • do {...} while (0) 在宏定义中的作用

    http www cnblogs com lanxuezaipiao p 3535674 html 如果你是一名C程序员 xff0c 你肯定很熟悉宏 xff0c 它们非常强大 xff0c 如果正确使用可以让你的工作事半功倍 然而 xff0c