C语言宏中的do{}while(0)和语句表达式
1. 宏中的do{}while(0)
请看下面一段代码:
#include <stdio.h>
#define swap(a, b) {int t = a; a = b; b = t;}
int main(void)
{
int x = 1;
int y = 2;
int z = 3;
if (x > y)
swap(x, y);
else
swap(y, z);
printf("%d %d %d\n", x, y, z);
return 0;
}
这段代码看着没有什么问题,但是编译的时候就会报错。这是因为在宏替换后
if (x > y)
swap(x, y);
else
swap(y, z);
变为了:
if (x > y)
{int t = a; a = b; b = t;};
else
{int t = a; a = b; b = t;};
注意{ }后的分号; ,这使得编译器认为if就这样结束了,后面的else由于没有匹配的if,编译报错。如果每条if语句都带上{},那么这个问题就解决了,如下代码:
if (x > y)
{
swap(x, y);
}
else
{
swap(y, z);
}
但是这并不能解决问题的实质。因此,有人想出了用do{}while(0)解决这个问题。
#define swap(a, b) do {int t = a; a = b; b = t;} while (0)
有没有其他的方法呢,其实还有一种比较好的方法,就是GUN C中有的语句表达式。
2. 语句表达式
GUN C把包含在括号中的复合语句看成是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环、局部变量等。例如:
#define min(x, y) ({ \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
代码行(void) (&_x == &_y)的作用是可以检查_x和_y的类型是否一致。
可以用这种方法解决上面出现的问题,即把宏改成如下形式:
#define swap(a, b) ({int t = a; a = b; b = t;})