C语言中宏定义(#define)时do{}while(0)的价值

最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总结了一下讨论,加上自己的理解,do{...}while(0)的价值主要体现在:

1. 增加代码的适应性

下面的宏定义没有使用do{...}while(0)

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

这样宏定义,单独调用不会出现问题,例如:

FOO(100)

宏扩展后变成:

1
foo(x);bar(x);

这样调用FOO没有任何问题,但是FOO(x)不能放入控制语句中,例如

1
2
3
4
if (condition)
    FOO(x);
else
    ...;

经过宏扩展后,变成了

if (condition)
foo(x);bar(x);
else
...;

这样就导致了语法错误,语法错误并不可怕,在编译阶段就能发现,更致命的是他有可能导致逻辑错误,这种错误编译器发现不了,一出这种问题,程序员就抓狂吧。例如:  

if (condition)
FOO(x);

这段代码经过扩展后变成:

if (condition)
foo(x); bar(x);

这样一来,无论condition是true还是false,bar(x)都会被调用。有没有被这煎熬过的兄弟啊?

这时候do{...}while(0)的价值就体现出来了,修改一下FOO的定义

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

这样FOO,放入控制语句中就没有问题了。

也许有人说:把foo(x);bar(x)用大括号括起来不就行了吗?比如这样定义:

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

再看下面代码:

if (condition)
FOO(x);
else
...;

扩展后:

if (condition)
{foo(x);bar(x);} ; //注意最后这个分号,语法错误
else
...;

照样语法错误;

2.增加代码的扩展性

我理解的扩展性,主要是宏定义中还可以引用其他宏,比如:

#define FOO(x) do{OTHER_FOO(x)} while(0)
这样我们不用管OTHER_FOO是但语句还是符合语句,都不会出现问题

3.增加代码的灵活性

灵活性主要体现在,我们可以从宏中break出来,例如下面的定义:

#define FOO(x)  do{ \
foo(x); \
if(condition(x)) \
break; \
bar(x) \
..... \
} while(0)

C语言中宏定义(#define)时do{}while(0)的价值(转)的更多相关文章

  1. C语言中宏定义#define 、 typedef 和枚举类型

    替换时机 #define :预编译阶段简单替换,编译阶段展开源程序(1.词法扩展==程序生成期间的字符串替换 2.语义扩展==生成特定指令) 枚举常量:编译阶段确定其值 内联函数:编译阶段插入代码 t ...

  2. c 语言中宏定义和定义全局变量的区别

    宏定义和定义全局变量的区别: 1 作用时间不同. 宏定义在编译期间即会使用并替换,而全局变量要到运行时才可以. 2 本质类型不同. 宏定义的只是一段字符,在编译的时候被替换到引用的位置.在运行中是没有 ...

  3. C语言中宏定义(#define)时do{}while(0)的价值

    最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总结了一下讨论,加上自己的理解,do{...}while(0)的价值 ...

  4. C语言中宏定义(#define)时do{}while(0)

    参考链接: http://www.cnblogs.com/fengc5/p/5083134.html 1.用于宏定义, 在该函数可以调用其它的宏,做其它内容的处理

  5. C语言中宏定义与C++中的内联函数

    一,宏定义:在预处理的时候把宏定义的内容替换到代码中,正常编译. 1,无参数宏定义和有参数宏定义 (1)宏定义不能加分号,比如:#define  PI 3.24;错的,#define  PI 3.24 ...

  6. c语言中宏定义和常量定义的区别

    他们有共同的好处就是"一改全改,避免输入错误"哪两者有不同之处吗?有的. 主要区别就在于,宏定义是在编译之前进行的,而const是在编译阶段处理的 宏定义不占用内存单元而const ...

  7. c语言中宏定义#和 ##的作用:

    转载:http://www.cnblogs.com/cyttina/archive/2013/05/11/3072969.html 看了这篇文章后了解了,但是文章中的例子比较特别,我在这里加个注释好了 ...

  8. C语言宏定义#define用法

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用 ...

  9. 宏定义#define整理

    一.宏定义#define 优点:一方面可以节省程序的空间上的篇幅,另外,恰当地使用宏定义可提高程序的时间效率.代码可以写的通俗易懂.可以提高程序的清晰性.可读性,使于修改移植等. 缺点:宏定义的使用实 ...

随机推荐

  1. 限制oracle用户创建、删除、修改用户对象

    在sys用户下执行: CREATE OR REPLACE TRIGGER lms2014BEFORE create or DROP OR ALTER ON databaseDECLAREBEGINIF ...

  2. Ubuntu系统下搭建Python开发环境

    之前演示了在Windows中安装Pycharm,很简单.下面介绍一下如何在Ubuntu中安装Pycharm 1.更新Python至3.5.1,执行以下命令: sudo add-apt-reposito ...

  3. Python多线程同步命令行模拟进度显示

    最近在一个Python(3.5)的小项目中需要用到多线程加快处理速度,同时需要显示进度,于是查了些资料找到几个实现方法:线程池的map-reduce和Queue结合线程的实现.这里简单的实例介绍一下Q ...

  4. 数字转化为人民币大写(PHP)

    <?php function numTrmb($num) { $d = array("零", "壹", "贰", "叁&qu ...

  5. 镜像树(dfs)

    1214: J.镜像树 时间限制: 1 Sec  内存限制: 64 MB提交: 18  解决: 7 标签提交统计讨论版 题目描述 一棵二叉树,若其与自己的镜像完全相同,就称其为镜像树(即这棵二叉树关于 ...

  6. 添加事件监听兼容IE6-8

    IE8一下浏览器不支持addEventListener,用attachEvent取而代之,但是在时间类型前面要加上’on‘,例如click时间在attachEvent中要写成onclick. var ...

  7. Match类

    Regex在匹配的时候,常常会返回一个Match类的对象,今天就来看看怎么玩这个对象. 一.属性 Captures 按从里到外.从左到右的顺序获取由捕获组匹配的所有捕获的集合(如果正则表达式用 Reg ...

  8. setAdapter(adapter)空指针nullPointer 解决办法

    setAdapter(adapter)空指针nullPointer 解决办法 (2014-06-13 10:01:23) 转载▼ 标签: 旅游 分类: Android开发 如果setAdapter报空 ...

  9. 2015第10周五CSS—2

    经常遇到的浏览器兼容性有哪些?如何解决? 1.浏览器默认的margin和padding不同.解决方案是加一个全局的*{margin:0;padding:0;}来统一. 2.IE6双边距bug:块属性标 ...

  10. bzoj1650 [Usaco2006 Dec]River Hopscotch 跳石子

    Description Every year the cows hold an event featuring a peculiar version of hopscotch that involve ...