有时候,你会发现,C语言中很多宏定义中使用了do-while(0)
比如,下面的这两个多条语句的宏定义(来源于头文件math.h)
/* Get a 32 bit int from a float. */
#ifndef GET_FLOAT_WORD
# define GET_FLOAT_WORD(i,d) \
do { \
ieee_float_shape_type gf_u; \
gf_u.value = (d); \
(i) = gf_u.word; \
} while (0)
#endif
/* Set a float from a 32 bit int. */
#ifndef SET_FLOAT_WORD
# define SET_FLOAT_WORD(d,i) \
do { \
ieee_float_shape_type sf_u; \
sf_u.word = (i); \
(d) = sf_u.value; \
} while (0)
#endif
有些人可能不理解,为什么要使用do-while(0)呢
不使用do-while(0)会有什么问题吗
下面我来做一下简单的说明
使用do-while(0)的目的是确保宏能被完整的执行
因为宏是简单的代码替换
对于含有多条语句的宏
如果不使用do-while(0)的结构
在某些情况下宏展开会出现错误
错误示例1
#define CUBE(a, b) \
a = a * a * a; \
b = b * b * b;
对于上面这种含有多条语句的宏定义
该宏没有使用大括号{}结构,没有使用if(0){}结构,也没有使用do-while(0)结构
如果使用下面的代码调用宏,就会出问题
if (a + b > 0)
CUBE(a, b);
本意是在a+b>0的情况下才会对a和b进行重新赋值
但是在实际上宏展开之后
由于if语句没有使用大括号{}
不管a+b>0条件是否成立
b = b * b * b;的语句都会执行,造成错误
错误示例2
#define CUBE(a, b) \
{
a = a * a * a; \
b = b * b * b; \
}
虽然使用了大括号{}的结构,但是在遇到下面这种情况还是会有问题
if (a + b > 0)
CUBE(a, b);
else
a = 0;
宏展开之后如下:
if (a + b > 0)
{
a = a * a * a;
b = b * b * b;
};
else
a = 0;
由于宏后面有个分号,会造成else匹配出现问题,造成错误
当然,如果你严格执行C的编程规范
上例中if后面的语句使用大括号{}括起来(哪怕只有一条语句)
也可以避免出现问题
但是我们还是强烈建议,对于多条语句的宏定义,要使用do-while(0)结构
#define CUBE(a, b) \
do { \
a = a * a * a; \
b = b * b * b; \
} while (0)
注意:
并不是所有的含有多条语句的宏定义都可以直接加do-while(0)结构
在含有break,goto等跳转语句的宏定义中一定要厘清代码的逻辑
如果加了do-while(0)有可能会改变代码逻辑
甚至会出现无法跳转出去的情况
尤其是在做代码整改的时候,要格外小心!!!