最近在看esp32的idf,有一些宏定义使用了do while(0)这种看起来好像没啥用的代码。然后我查了一下资料,发现在linux内核代码中经常用到这个东西!

现在就将这个东西整理一下。

为什么在内核中碰到很多

#define ...  do{...} while(0) 

有以下几点原因:

1、空语句在编译的时候会出现警告,所以有必要用#define FOO do{ } while(0)

2、给定一个基本块,可以在里面定义局部变量

3、为了能够在条件语句中使用复杂的宏定义。例如下面这段代码:

#define FOO(x) 

     printf("arg is %s\n", x); 

     do_something_useful(x);

如果这样用:

    if (blah == )    F00(blah);

将会被展开为:

  if (blah == )

              printf("arg is %s\n", blah);

              do_something_useful(blah);

这样,if条件之后包含了printf()语句,而do_something_useful()调用不能按照预期那样工作。

而用do {...} while(0)定义后,就会展开成以下语句:

if (blah == )

do{

              printf("arg is %s\n", blah);

              do_something_useful(blah);

}while();

这是我们所期望的。

如果你希望定义一个包含多行语句和一些局部变量的时候. 一般的定义方式只能这样:

#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }

然而在某些情况下,这样并不能正常工作. 下面是包含两个分支的if语句:

 if (x > y)

  exch(x,y);          // Branch 1

  else

  do_something();     // Branch 2

但这样却只能展开成单分支的if语句,如下:

if (x > y) {                // 单分支if

  int tmp;

  tmp = x;

  x = y;

  y = tmp;

  }

  ;                           // 空语句

  else                        // 语法错误! "parse error before else"

  do_something();

问题是由于在语句块后直接加入分号(;)引起的。

解决办法是将语句块放入 do 和 while (0)中间.这样就得到了一条单语句, 而不是被编译器判断为语句块.现在的if语句如下:

if (x > y)

  do {

      int tmp;

      tmp = x;

      x = y;

      y = tmp;

  } while();

 else

  do_something();

假设有这样一个宏定义

#define  macro(condition)  if(condition)  do_something();  

现在在程序中这样使用这个宏:

if(temp)
macro(i);
else
do_anotherthing();

一切看起来很正常,但是仔细想想。这个宏会展开成:

if(temp)
if(condition) do_something();
else
do_anotherthing();

这时的else不是与第一个if语句匹配,而是错误的与第二个if语句进行了匹配,编译通过了,但是运行的结果一定是错误的。  
 
为了避免这个错误,我们使用do{….}while(0)  把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低。

参考资料

http://blog.csdn.net/chenhu_doc/article/details/856468

http://www.233.com/linux/fudao/20101102/140715235.html

嵌入式编程中使用 do{...} while(0) 的解释的更多相关文章

  1. union 的概念及在嵌入式编程中的应用

    union 概念 union 在中文的叫法中又被称为共用体,联合或者联合体,它定义的方式与 struct 是相同的,但是意义却与 struct 完全不同,下面是 union 的定义格式: union ...

  2. 在嵌入式开发中应该这样理解嵌入式C编程

    一.新手常常问的一个问题:C语言和嵌入式C编程有什么区别?而嵌入式工程师一般都会告诉你,其区别在于嵌入式的C语言是跑在嵌入式的开发板上的,CPU和电脑不一样,所以编译器也是不一样的,生成的可执行程序也 ...

  3. paip.提升性能--多核编程中的java .net php c++最佳实践 v2.0 cah

    paip.提升性能--多核编程中的java .net php c++最佳实践  v2.0 cah 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax ...

  4. Android编程中的5种数据存储方式

    Android编程中的5种数据存储方式 作者:牛奶.不加糖 字体:[增加 减小] 类型:转载 时间:2015-12-03我要评论 这篇文章主要介绍了Android编程中的5种数据存储方式,结合实例形式 ...

  5. 外围功能电路控制 LET′S TRY“嵌入式编程”: 4 of 6

    外围功能电路控制 LET′S TRY“嵌入式编程”: 4 of 6 本连载讲解作为嵌入式系统开发技术人员所必需具备的单片机的基础知识. 在<单片机入门(1)-(3)>中,我们一起学习了单片 ...

  6. 单片机的编程语言和开发环境 LET′S TRY“嵌入式编程”: 3 of 6

    单片机的编程语言和开发环境 LET′S TRY“嵌入式编程”: 3 of 6 本连载讲解作为嵌入式系统开发技术人员所必需具备的基础知识.这些基础知识是硬件和软件技术人员都应该掌握的共通技术知识. 在“ ...

  7. 单片机的外围功能电路 LET′S TRY“嵌入式编程”: 2 of 6

    单片机的外围功能电路 LET′S TRY“嵌入式编程”: 2 of 6 本连载讲解作为嵌入式系统开发技术人员所必需具备的基础知识.这些基础知识是硬件和软件技术人员都应该掌握的共通技术知识. 上期在&l ...

  8. 单片机的基本构成、工作原理 LET′S TRY“嵌入式编程”: 1 of 6

    单片机的基本构成.工作原理 LET′S TRY“嵌入式编程”: 1 of 6 本连载讲解作为嵌入式系统开发技术人员所必需具备的基础知识.这些基础知识是硬件和软件技术人员都应该掌握的共通技术知识.有了电 ...

  9. Linux Shell编程中的几个特殊符号命令 & 、&& 、 ||

    https://blog.csdn.net/hack8/article/details/39672145 Linux Shell编程中的几个特殊符号命令 & .&& . || ...

随机推荐

  1. idea选中文件时左侧菜单自动定位到文件所在位置

    一:设置成自动定位,如图: 二:点击项目工程目录上的阻击按钮,自动定位

  2. bootstrap创建带遮罩层的进度条

    <div class="modal fade" id="loadingModal"> <div style="width: 200p ...

  3. Hadoop3.1.1源码Client详解 : Packet入队后消息系统运作之ResponseProcessor(ACK接收)

    该系列总览: Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览 紧接着上一篇文章: Hadoop3.1.1源码Client详解 : Packet入队后消息系统运作之D ...

  4. awk函数实现将点分式形式的掩码转换为十进制形式的掩码

    在用awk处理文本时,需要将源数据为点分式形式的掩码转换为十进制形式的掩码,下边的函数可简单实现: 转换功能函数cdr2mask function cdr2mask(mask_point) { num ...

  5. Dart语言学习(三)Dart数值型

    一.类型 数值型有 num,int, double  num a = ; a = 12.5; print(a); print(a.runtimeType); ; // b = 20.5; print( ...

  6. Web基础了解版08-JSTL-Core标签库

    JSTL JSP为我们提供了可以自定义标签库(Tag Library)的功能,用来替代代码脚本,Sun公司又定义了一套通用的标签库名为JSTL(JSP Standard Tag Library),里面 ...

  7. opencv:自定义滤波

    卷积核的定义 均值卷积核 // 自定义滤波 - 均值卷积 int k = 15; Mat mkernel = Mat::ones(k, k, CV_32F) / (float)(k * k); Mat ...

  8. PAT 1017 Queueing at Bank (模拟)

    Suppose a bank has K windows open for service. There is a yellow line in front of the windows which ...

  9. KafKa集群安装、配置

    一.事前准备 1.kafka官网:http://kafka.apache.org/downloads. 2.选择使用版本下载. 3.kafka集群环境准备:(linux) 192.168.145.12 ...

  10. 城市间紧急救援 Dijkstra

    作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图.在地图上显示有多个分散的城市和一些连接城市的快速道路.每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上.当其他城市有紧急求 ...