短路评估和副作用[重复]
Posted
技术标签:
【中文标题】短路评估和副作用[重复]【英文标题】:Short circuit evaluation and side effects [duplicate] 【发布时间】:2011-04-07 20:03:10 【问题描述】:好吧,我有点不好意思问这个问题,但我只是想确定一下……
众所周知,C 在布尔表达式中使用短路求值:
int c = 0;
if (c && func(c)) /* whatever... */
在该示例中,func(c)
未被调用,因为 c
的计算结果为 0
。但是,如果比较的副作用会改变接下来要比较的变量,那么更复杂的例子呢?像这样:
int c; /* this is not even initialized... */
if (canInitWithSomeValue(&c) && c == SOMETHING) /*...*/
函数canInitWithSomeValue
返回真并在成功的情况下改变给定指针的值。是否保证后续比较(本例中为c == SOMETHING
)使用canInitWithSomeValue(&c)
设置的值?
不管编译器使用了多么重的优化?
【问题讨论】:
我认为您可能会混淆短路评估和编译器优化。在第一个示例中,编译器将优化掉整个if
语句,因为它永远无法运行。短路评估意味着如果您有 if(func1() && func2()) ...
,并且 func1() 在运行时 评估为假(即在编译时不明确),那么代码不应检查 func2()
- 编译器应该精心设计机器代码,如果func1()
为假,则不会调用func2()
。
int c = 0
在比较时表明c
等于0
,我意识到在这种简单的情况下编译器会优化整个if
。
啊,我很抱歉。我误读了你。我很抱歉。
【参考方案1】:
是否保证后续比较(本例中为 c == SOMETHING)使用由 canInitWithSomeValue(&c) 设置的值?
是的。因为有一个sequence point
在
&&
(逻辑与)、||
(逻辑或)和逗号运算符的左右操作数的求值之间。例如,在表达式*p++ != 0 && *q++ != 0
中,子表达式 *p++ != 0 的所有副作用都在尝试访问 q 之前完成。
序列点定义了计算机程序执行中的任何点,在该点可以保证先前评估的所有副作用都已执行,并且后续评估的副作用尚未执行。
【讨论】:
【参考方案2】:是的。因为&&
和||
运算符也称为序列点。后者定义了前一个操作的副作用何时应该完成,而下一个操作的副作用不应该开始。
【讨论】:
【参考方案3】:if 语句复合条件内的求值严格从左到右。唯一会优化 if 中的第二个测试的情况是编译器是否可以 100% 确定第一个测试完全等于 false。
【讨论】:
以上是关于短路评估和副作用[重复]的主要内容,如果未能解决你的问题,请参考以下文章