c++tricks——do{...}while(0)技巧

在一些开源的库项目中,经常看到作者在定义包含大量语句的宏时,使用do{...}while(0)封装。如:

#definemacro(cond)\

do{\

  if(cond)\

    dosomething();\

}while(0);

这样做的目的是什么?

首先看一个例子,定义一个宏,其中包括与上例相同的条件语句,但不使用封装

#definemacro1(cond)\

  if(cond)\

   dosomething();

然后在如下的场景中使用宏:

//code-1

if(cond1)

  macro1(cond2)

else

  dosomething();

按照c/c++标准规定,else与最近的if语句匹配,将宏展开后,如下:

//code-2

if(cond1)

  if(cond2)

    dosomething();

else

  dosomething();

恩恩,恩?!
不对啊,大哥,我好像要得不是这个啊。到这里估计有一些朋友还没有反应过来,让我们返回去看code-1。实际上我们在code-1是想让else匹配外面那个if的,然而当预编译后成了code-2,else就变成和里面的if匹配了。正是因为编写者将多条代码用一句宏代表了,让调用者产生了宏函数只是一句代码的错觉,特别当宏不是调用者写的时候,很容易忽略这个问题。而且最可怕是,编译器不会报错,甚至程序运行后也可能不会报错,但就是通不过测试,而且还要加上宏函数在调试上的困难...还是别这么写代码了吧...

那么宏函数这种模式就一无是处了么?其实不然,这种模式最大的优点是执行效率高,为什么这么说,因为宏函数的调用不会为cpu带来函数跳转的开销,同时提高代码复用率,当然也会带来诸如难调试,可读性差等问题,建议非高手不为。

话题扯回来,为了杜绝上述二义性,有两种解决思路:

1)使用{...}包裹语句块

如上述场景下,使用大括号封装:

#definemacro1(cond)\

{\

  if(cond)\

    dosomething();\

}

是的,这样包装语句块也不会造成二义性,并且使用大括号包装语句还能制造一片局部作用域,实现一些py交易。但是这样做也有一个问题,就是分号";"问题。

如下:

#define AB2 { a; b; }


if(cond)

  AB2;

else

  ...

很普通对不对,然而编译报错,因为{...}后面除了class{...};编译器不会报错(且是必须的),函数中是不允许这种语法的...还是那个原因,调用这个宏的人不一定知道这个宏的实现啊...

那么还剩下一种方法,那就是用do{...}while(0)

2使用do{...}while(0)包裹

#definemacro1(cond)\

do{\

  if(cond)\

   dosomething();\

}while(0);

优点:

1>独立作用域,语法单元,不会和上下文混淆
2>没有分号的问题
3>循环实际上不执行,且大多数编译器都会做优化,不会影响程序性能。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值