假如你是一名C措施员,你必定很熟悉宏,它们很是强大,假如正确利用可以让你的事情事半功倍。然而,假如你在界说宏时很随意没有当真查抄,那么它们大概使你发疯,挥霍N多时间。在许多的C措施中,你大概会看到很多看起来不是那么直接的较非凡的宏界说。下面就是一个例子:
#define __set_task_state(tsk, state_value) \
do{ (tsk)->state = (state_value); } while(0)
在Linux内核和其它一些著名的C库中有很多利用do{…}while(0)的宏界说。这种宏的用途是什么?有什么长处?
Google的Robert Love(先前从事Linux内核开拓)给我们解答如下:
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)的环境下。
假如我们利用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);
从语义上讲,它与下面的语句是等价的:
if (!feral) {
bar(wolf);
baz(wolf);
}
这里你大概感想疑惑不解了,为什么不消大括号直接把宏困绕起来呢?为什么非得利用do/while(0)逻辑呢?
譬喻,我们用大括号来界说宏如下:
#define foo(x) { bar(x); baz(x); }
这对付上面举的if语句简直能被正确扩展,可是假如我们有下面的语句挪用呢:
if (!feral)
foo(wolf);
else
bin(wolf);
宏扩展后将酿成:
if (!feral) {
bar(wolf);
baz(wolf);
};
else
bin(wolf);
各人可以看出,这就有语法错误了。
总结:Linux和其它代码库里的宏都用do/while(0)来困绕执行逻辑,因为它能确保宏的行为老是沟通的,而不管在挪用代码中利用了几多分号和大括号。
From:csdn博客 lanxuezaipiao