我们在C代码中经常会使用#define去定义宏。在Linux内核代码或是一些比较大型的C项目中,我们经常会见到类似“do {...} while (0)”的宏。那么这样写到底是为什么呢?其实原因很简单——为了避免在不同场景中宏替换产生错误。我们都知道宏在代码预处理阶段会被展开,而这个展开就是简单的文本替换。这里是非常容易出错的。下面我们举一些例子来说明。
定义下面宏:
#define foo(x) bar(x); baz(x)
某A处调用:
foo(wolf);
展开后使我们预期的:
bar(wolf); baz(wolf);
再看某B处调用:
if (!feral)
foo(wolf);
展开后并不是我们预期的:
if (!feral)
bar(wolf);
baz(wolf);
但是我们如果使用do{...}while(0)宏来写,就可以正常替换了:
#define foo(x) do { bar(x); baz(x); } while(0)
这样刚才某B处的调用展开后为:
if (!feral)
do { bar(wolf); baz(wolf); } while(0);
这显然就是对的了。看到这,也许有人会说,上面的语句不就等效于:
if (!feral)
{ bar(wolf); baz(wolf); }
那我们将宏定义成如下样子不就可以了:
#define foo(x) { bar(x); baz(x); }
其实这样在某些场景下也是不行的:
if (!feral)
foo(wolf);
else
bin(wolf);
这样的语句展开后为:
if (!feral)
{ bar(wolf); baz(wolf); };
else
bin(wolf);
显然,是有语法错误的。所以使用do{…}while(0)的写法是非常具有通用性和安全的。
个人之见:现在C中已经有const和内联函数(inline)了,所以我们尽量就不要再使用#define宏去定义函数了,特别是一些复杂的函数,不仅不便于调试,而且也很容易出错。
评论已关闭