括号和逻辑运算符

4

考虑以下代码(C ++):

int x = -4 , y = 5 ;
bool result = x > 0 && y++ < 10 ;

表达式(x>0)将首先被评估,因为(x>0=false),由于短路评估,另一个表达式(y++<10)不会被评估,y的值将保持为5。

现在考虑以下代码:

int x = -4 , y = 5 ;
bool result = (x > 0) && (y++ < 10) ;

预期在括号中的表达式将会首先被计算,这意味着在执行逻辑“与”操作之前,表达式(y++ < 10)已经被计算并且y的值变成了6,但事实上,y仍然等于5。这意味着即使使用了括号也进行了短路处理,表达式(y++ < 10)被忽略了。

这种情况的解释是什么?!


1
“预计括号中的表达式将首先被评估”-- 错误。 括号不起任何作用,在这两种情况下,x>0始终首先被评估。 - Adam Rosenfield
1
括号可以覆盖优先级,但评估顺序与优先级无关。评估顺序由序列点(C、C++98/03)或排序约束(C++11)确定,而不是优先级或结合性。 - Jerry Coffin
只有当 && 出现时,右侧才会被评估。虽然您正确地指出在数学中应该先评估括号,但布尔逻辑有点不同,因为它从左到右保证运算。 - Benjamin Danger Johnson
3个回答

10

问题已经在问题描述中解释了 - 短路求值

在 C++ 中,&& 的计算(以及 || )保证是从左到右的,只要遇到一个 false(或者对于 ||true),计算就保证停止。

Java 同理。

在这种情况下,括号是多余且无关紧要的 - 它与运算符优先级无关。它只与 && 的工作方式有关:

实际上,这两个版本

x > 0 && y++ < 10
(x > 0) && (y++ < 10)

这两种表达式是等价的,因为++的优先级最高,其次是<,>,最后是&&。严谨地说,你应该将其写成:

(x > 0) && ((y++) < 10)

5.14 逻辑与运算符 [expr.log.and]

1 运算符 && 的分组方向是从左到右。操作数都会被隐式转换为布尔类型 (第4条款)。如果两个操作数都是 true,则结果为 true,否则为 false。与 & 不同的是,&& 保证左到右的求值顺序:如果第一个操作数为 false,则不会对第二个操作数进行求值。(我强调)


Java有非短路AND(&)和OR(|)。 - Steve Kuo
@SteveKuo 这些是位运算符,C++ 版本也不支持短路。 - Luchian Grigore

1

当左侧确定结果时,右侧不会被评估。

在第一种情况下,右侧是y++ < 10,这不会被评估。在第二种情况下,右侧是(y++ < 10),这也不会被评估。

没有规则表明括号中的表达式首先被评估。括号只是将操作数分组。


0
即使使用括号短路,必须仍然发生。考虑一下如果您有涉及指针的表达式:
int* ptr = 0;
int bar = 5;
bool result = (ptr != 0) && (*ptr == bar || bar > 10);

显然,您无法安全地评估&&的右侧,但是需要使用括号来使优先级按预期工作。括号仅确定实际执行的操作顺序,而不是它们以特定顺序发生。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接