C++-为什么有时候在C/C++宏里,有毫无意义的do/while和if/else块?

发布于 2017-07-01 21:39:30 字数 259 浏览 1191 评论 10

在很多C/C++宏里我发现有很多貌似无任何实际意义的do/while或者if/else代码块。比如:

#define FUNC(X) do { f(X); g(X); } while (0)
#define FUNC(X) if (1) { f(X); g(X); } else

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

虐人心 2017-11-08 08:02:18

一般情况下来说是为了防止宏的副作用,但是在不同的具体应用环境下可能有不同,可以把应用的环境贴出来看看

归属感 2017-10-12 07:02:17

楼上说得很到位,其实cC++中的宏非常强大,可以实现很多高级功能,比如(#),(#@),(##)的使用。你看看MSDN上的#define讲解,我相信很多cC++程序员没去MSDN上查过#define。

想挽留 2017-10-12 01:04:13

宏定义最基本的需要把所有定义的东西用括号括起来吧?

灵芸 2017-10-10 22:11:17

do { f(X); g(X); } while (0)

这种写法确实是为了在某些情况下(调用函数出错,不能继续往下执行)
可以用break跳出来,这种做法叫做“统一出口”,类似于用goto,
目前来讲很多程序员或者公司都保留goto的这个作为统一出口的习惯用法。
而且非常有用。

泛泛之交 2017-10-10 11:25:00

你是在MFC下看到的代码吧,WINDOWS里经常使用这样的方式定义宏变量,这样可以有效的防治函数宏产生的副作用,同时,对于这样的宏,可以放心的调用。

偏爱自由 2017-10-03 08:05:56

#define FUNC(X) if (1) { f(X); g(X); } else

这个是为了保证语言执行的完整性,把这个执行过程展开一下你就明白了

比如:

if(true)
FUNC(x);
else
dosomething();

宏展开后成为如下代码:

if (true)
f(x); g(x);
else
dosomething();
这时执行完f(x)后,会自动跳出if(true),不执行g(x)了
所以执行到这里,就很容易明白了,这个宏这是为了保证可以连续执行
{ f(X); g(X); }

#define FUNC(X) do { f(X); g(X); } while (0)

这个有三方面的原因
1.单纯为了避免使用goto语句
2.如果用if代替do{..}while(0),因为if分支后有两个语句,else分支没有对应的if,编译错误,假设没有else, 第二个语句无论if测试是否通过,会永远执行。

以上二点,所以才会有了#define FUNC(X) do { f(X); g(X); } while (0)

一言以蔽之,就是#define FUNC(X) if (1) { f(X); g(X); } else有些情况下无法满足,所以用#define FUNC(X) do { f(X); g(X); } while (0)进行了扩展

归属感 2017-10-02 13:22:12

这么做在我看来有如下几点考虑:

do/while 保证了这段代码只执行一次而无需关心do/while内部代码。
组织更高效的代码,在do/while包含中的代码,在编译的以后被作为一段完整的代码块。
还有就是保证语句的完整执行和语法错误,例如f(x)或者g(x)代码中有if分支语句,要是没有do-while把多条语句组织成一个代码块,则程序的运行结果就不正确,甚至不能编译。
通过内敛宏定义的这段代码,编译后省去了函数指针的调用,本身作为代码块节省了空
间。

对于非求值的宏,即代码块宏,用do {....}while(0)包围代码块,防止产生意外代码。
倘若使用{}包围代码,可能出现错误代码。比如:

  #define boo()
{
....
}

在if语句中使用它,
if(x)
b00();
else
...

然而上述代码不能如预期的工作,展开后为
if(x)
{
....
}
;
else
...

可见多出了一个';',但使用do...while(0)不会出现此问题。
do...while(0)似乎多了一个不必要的循环,不过编译器优化时会识别。
do...while(0)另一用处在于避免goto语句的使用,比如:
do {
if(...)
break;/*不满足要求跳出*/
.....

if(...)
break;/*不满足要求跳出*/
.....

return;/*成功*/
}while(0)
..../*不满足后的处理*/

灵芸 2017-08-31 07:12:38

如果 f、g 是宏定义,那么这种定义多半是为了break跳出方便。另外补充一点对于#define FUNC(X) if (1) { f(X); g(X); } else
这个定义,在使用时如果后面不加“;”有屏蔽下一条语句的影响,编译不会报错,所以这是一个比较危险的定义,慎用!。

夜无邪 2017-07-17 16:24:06

如果f和g是函数,这俩例子确实没必要,顶多加个花括号吧;
如果f和g是宏,得看它们的内部处理了,比如对do,某些条件直接break就能跳过后续的代码;
通常见到的这种应用都不是这么简单的形式吧。

灵芸 2017-07-17 10:35:54

大家说得都挺好,宏只是简单的代码替换,加入这些是为了防止宏替换代码时对上下文产生副作用。对宏的使用看似简单,但真正用好挺不容易的。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文