实际上,do{…}while(0)的作用远大于美化你的代码。
总结起来这样写主要有以下几点好处:

1. 辅助定义复杂的宏

避免引用的时候出错:
举例来说,假设你需要定义这样一个宏:


#define DOSOMETHING()\
foo1();\
foo2();

这个宏的本意是,当调用DOSOMETHING()时,函数foo1()和foo2()都会被调用。但是如果你在调用的时候这么写:


if(a>0)
DOSOMETHING();

因为宏在预处理的时候会直接被展开,你实际上写的代码是这个样子的:


if(a>0)
foo1();
foo2();

这就出现了问题,因为无论a是否大于0,foo2()都会被执行,导致程序出错。
那么仅仅使用{}将foo1()和foo2()包起来行么?

我们在写代码的时候都习惯在语句右面加上分号,如果在宏中使用{},代码里就相当于这样写了:“{…};”,展开后就是这个样子:


if(a>0)
{
foo1();
foo2();
};

这样甚至不会编译通过。所以,很多人才采用了do{…}while(0);


#define DOSOMETHING() \
do{ \
foo1();\
foo2();\
}while(0)\ ... if(a>0)
DOSOMETHING();

这样,宏被展开后,才会保留初始的语义。
GCC提供了Statement-Expressions用以替代do{…}while(0) ;
所以你也可以这样定义宏:


#define DOSOMETHING() ({\
foo1(); \
foo2(); \
})

2. 避免使用goto对程序流进行统一的控制

有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,goto一直都是一个比较简便的方法:


int foo()
{
somestruct* ptr = malloc(...); dosomething...;
if(error)
{
goto END;
} dosomething...;
if(error)
{
goto END;
}
dosomething...; END:
free(ptr);
return 0; }

由于goto不符合软件工程的结构化,而且有可能使得代码难懂,所以很多人都不倡导使用,那这个时候就可以用do{}while(0)来进行统一的管理:


int foo()
{ somestruct* ptr = malloc(...); do{
dosomething...;
if(error)
{
break;
} dosomething...;
if(error)
{
break;
}
dosomething...;
}while(0); free(ptr);
return 0;
}

这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。

3. 避免空宏引起的warning

内核中由于不同架构的限制,很多时候会用到空宏,在编译的时候,空宏会给出warning,为了避免这样的warning,就可以使用do{}while(0)来定义空宏:

    #define EMPTYMICRO do{}while(0)

4. 定义一个单独的函数块来实现复杂的操作:

当你的功能很复杂,变量很多你又不愿意增加一个函数的时候,使用do{}while(0);将你的代码写在里面,里面可以定义变量而不用考虑变量名会同函数之前或者之后的重复。

(C)do{...}while(0);的用法及意义的更多相关文章

  1. linux find命令中-print0和xargs中-0的用法

    linux find命令中-print0和xargs中-0的用法. 1.默认情况下, find命令每输出一个文件名, 后面都会接着输出一个换行符 ('\n'), 因此find 的输出都是一行一行的: ...

  2. do{...}while(0)的用法

    零.导引第一次见到 do{...}while(0)是在学习libevent的时候,看到里面有很多类似#define TT_URI(want) do { \ char *ret = evhttp_uri ...

  3. Cocos2d-x 3.0 Json用法 Cocos2d-x xml解析

    Cocos2d-x 3.0 加入了rapidjson库用于json解析.位于external/json下. rapidjson 项目地址:http://code.google.com/p/rapidj ...

  4. basename $0的用法

    basename 从文件名中去掉路径信息, 只打印出文件名. 结构 basename $0 可以让脚本知道它自己的名字, 也就是, 它被调用的名字. 可以用来显示用法信息, 比如如果你调用脚本的时候缺 ...

  5. (27)Cocos2d-x 3.0 Json用法

    Cocos2d-x 3.0 加入了rapidjson库用于json解析.位于external/json下. rapidjson 项目地址:http://code.google.com/p/rapidj ...

  6. git tag的用法及意义

    git tag 介绍 命令是用来给当前项目状态(在某次commit后)打标签的,目的是便于以后将项目状态回滚到当时打标签的状态.可以把它与虚拟机的snapshot(快照)进行类比. 回想当时在看< ...

  7. ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]的用法

    父类:public class BaseHibernateDaoSupport<T>{ private Class<T> entityClass; public BaseHib ...

  8. 新浪微博OAuth2.0的用法

    最近学习Android开发,照着视频开发新浪微博,但是视频里的介绍的是OAuth1.0的授权方式,试了半天发现用不了. 原来现在一般没审核的用户只能使用OAuth2.0了,视频教学里的方法已经过时了. ...

  9. href="javascript:void(0)" 的用法

    href=”javascript:void(0);”这个的含义是,让超链接去执行一个js函数,而不是去跳转到一个地址,而void(0)表示一个空的方法,也就是不执行js函数. 为什么要使用href=” ...

随机推荐

  1. ecplise 使用快捷键

    1. [ALT+/]    此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ALT+/]快捷键带来的好处吧.    2. ...

  2. Aragorn's Story(hdu3966)

    题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的路径上的所有点权值减去K Q C:查询节点编号为C ...

  3. Peaks BZOJ 3545 / Peaks加强版 BZOJ 3551

    Peaks [问题描述] 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问 ...

  4. ObjectDataSource配合存储过程(采用数据集)的使用(删除可以解决,但是编辑出错好像它的方法也无法解决

    原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] ObjectDataSource是比较有意思的一个东西 通过在网络上遍访各位高手,终于自己有了一些心得体会。现总结 ...

  5. commons.apache

    1.ToStringBuilder //对象及其属性一行显示 System.out.println(ToStringBuilder.reflectionToString(u)); System.out ...

  6. oracle-统计员工x

    1. SELECTe.depid,avg(s.bonussalary+s.basesalary) AS avgsal from employ e,salary s where e.employId=s ...

  7. scp操作实例

    scp 可用于文件的上传与下载,默认端口号是22,通常我们为了安全起见会将默认端口号修改了,而不去直接使用默认的22端口,以下我们以8888端口为例 目标机器 A :192.168.10.30 目标机 ...

  8. 辅助方法 @Html.Raw与 HtmlString区别

    //Html.Raw其实是调用 new Microsoft.AspNetCore.Html.HtmlString(xxx) @{ ViewData["Title"] = " ...

  9. 64-bit Itanium与x64

    64-bit Itanium是什么意思 64-bit Itanium,指的是intel 安腾处理器,intel安腾处理器是Intel的某一代处理器,当然是在酷睿(即core)这一代之前出来的. ora ...

  10. Swift标识符和keyword

    不论什么一种计算机语言都离不开标识符和keyword,下面我们将具体介绍Swift标识符和keyword. 标示符 标识符就是给变量.常量.方法.函数.枚举.结构体.类.协议等指定的名字.构成标识符的 ...