建议各位程序员跳过本文, 直接查看原文.
你也许看到了一个条件表达式是常量0的do循环.它创建了只会执行一次的的循环. 这种编程方法可以将多行的宏放在任何只能用一条语句的地方.
由于do循环的条件表达式是一个常量, 编译器不会生成额外的代码来处理循环, 所以当执行这段代码时, 这种方法不会增加多余的操作.
这种技术在宏定义中频繁使用, 尤其是宏的内容较复杂(如多条语句)时. 由于不知道宏被用在哪儿, 所以使宏满足被替换后所需要的语法很重要. 例如: 下面的宏用一条语句替换两条语句.
#define foo \ statement_1; \ statement_2
如果把此宏用到以下if语句中, 不会产生预期的效果:
if (condition) foo;
替换宏后, if条件后面跟着两条语句, 这大概不是你想要的, 因为if语句只控制了第一条语句的执行.
if (condition) statement_1; statement_2;
接下来的例子使用do循环方法重写. 注意, 在定义中没有结尾的分号, 分号将会由被替换的语句提供.(译者注: 这样子使得调用宏的语句起来更像条合法的语句. 如果宏定义中有分号, 那么调用宏时不用加分号, 看起来会很唐突.)
#define foo \ do { \ statement_1; \ statement_2; \ } while (0)
现在, 使用该宏时, 正如你预期的那样, if条件后面跟的是一条语句.(译者注: 以下语句是展开后的结果)
if (condition) do { statement_1; statement_2; } while (0);
当宏中只包含if语句不包含else语句时, 也会发生类似的问题.
#define foo \ if (condition) \ statement
如果该宏用在有else语句的if语句中, 宏中的if将会偷走跟在它后面的else语句.
if (condition) foo; else bar;
虽然else语句的缩进表明它属于第一个if语句, 但是它与第二个else语句结合.
if (condition) if (condition) statement; else bar;
如果在该例子中使用do循环方法, if语句将会在宏中结束, 所以不会偷走下面的else语句.
if (condition) do { if (condition) statement; } while (0); else bar;
使用空的do-while(0)循环也是一种定义空语句宏的通用方法. 在旧编译器中, 防止编译器产生警告是有必要的, 例如:
#define do_nothing do {} while (0)
现在的gcc编译器提供了另一种可以替换do-while的方法, 例如:
#define foo ({ \ statement_1; \ statement_2; \ })
翻译完毕.
译者注:以下是linux 2.4.31内核的max实现:
#define max(x,y) ({ \ const typeof(x) _x = (x); \ const typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; })
为了避免重复计算max的参数, 宏定义中使用了typeof, typeof是GNU的扩展, 用来取表达式的类型, typeof貌似不会计算表达式的值. 我会另开帖子来介绍max函数.
原文链接:
Bruce Blinn: do {} while(0)
Reference:
Bit Twiddling Hacks
GCC doc: Referring to a Type with typeof