在Linux内核和其它一些著名的C库中有许多使用do{...}while(0)的宏定义。这种宏的用途是什么?有什么好处?
do{...}while(0)在C中是唯一的构造程序,让你定义的宏总是以相同的方式工作,这样不管怎么使用宏(尤其在没有用大括号包围调用宏的语句),宏后面的分号也是相同的效果。
其实用一句话概括就是:使用do{...}while(0)构造后的宏定义不会受到大括号、分号等的影响,总是会按你期望的方式调用运行。
例如:
#define foo(x) bar(x); baz(x)
foo(wolf);
// 这样调用将被宏扩展为
bar(wolf); baz(wolf);
// 是正确的输出
if (!feral)
foo(wolf);
// 这样调用后宏展开就不是期望的结果
if (!feral)
bar(wolf);
baz(wolf);
// 如果我们使用do{...}while(0)来重新定义宏,即:
#define foo(x) do { bar(x); baz(x); } while (0)
// 现在,该语句功能上等价于前者,do能确保大括号里的逻辑能被执行
// 而while(0)能确保该逻辑只被执行一次,即与没有循环时一样。
// 对于上面的if语句,将会被扩展为:
if (!feral)
do { bar(wolf); baz(wolf); } while (0);
为什么不用大括号直接
把宏包围起来呢?为什么非得使用do/while(0)逻辑呢?
#define foo(x) { bar(x); baz(x); }
// 这样调用后宏展开就不是期望的结果
if (!feral)
foo(wolf);
else
bin(wolf);
// 宏展开后存在语法问题
if (!feral) {
bar(wolf);
baz(wolf);
};
else
bin(wolf);
总结:Linux和其它代码库里的宏都用do/while(0)来包围执行逻辑,因为它能确保宏的行为总是相同的,而不管在调用代码中使用了多少分号和大括号。