在C ++中,为什么真正的&&真||虚假&& false ==是吗?

时间:2010-10-31 05:06:32

标签: c++ boolean-logic short-circuiting boolean-expression

我想知道是否有人知道编译器解释以下代码的方式:

#include <iostream>
using namespace std;

int main() {
 cout << (true && true || false && false) << endl; // true
}

这是真的,因为&amp;&amp;优先级高于||或因为||是一个短路运算符(换句话说,短路运算符是否忽略所有后续表达式,或只是下一个表达式)?

12 个答案:

答案 0 :(得分:34)

&&的优先级高于||

答案 1 :(得分:29)

答案 2 :(得分:22)

答案 3 :(得分:7)

&&确实有higher precedence

答案 4 :(得分:7)

两个事实解释了两个例子的行为。首先,&&的优先级高于||。其次,两个逻辑运算符都使用短路评估。

优先级往往与评估顺序混淆,但它是独立的。只要最终结果正确,表达式可以按任何顺序评估其各个元素。通常对于某些运算符来说,这意味着左边的值(LHS)可以在右边的值(RHS)之前或之后进行评估,只要在应用运算符本身之前对它们进行求值即可。

逻辑运算符具有特殊属性:在某些情况下,如果一方评估为特定值,则无论另一方的值如何,都知道运算符的值。为了使这个属性有用,C语言(以及每个类C语言的扩展)指定了逻辑运算符来评估RHS之前的LHS,并进一步仅评估RHS,如果其值 required 了解运营商的结果。

因此,假设TRUEFALSE的通常定义,TRUE && TRUE || FALSE && FALSE从左侧开始计算。第一个TRUE不强制第一个&&的结果,因此评估第二个TRUE,然后评估表达式TRUE && TRUE(为TRUE)。现在,||知道它的LHS。更好的是,它的LHS迫使||的结果被人知道,因此它会跳过对整个RHS的评估。

完全相同的评估顺序适用于第二种情况。由于||的RHS无关紧要,因此不会对其进行评估,也不会调用infiniteLoop()

此行为是设计使然,非常有用。例如,您可以编写p && p->next知道该表达式永远不会尝试取消引用NULL指针。

答案 5 :(得分:3)

  

“如果发生||运算符短路并使第二个&amp;&amp;表达式的执行短路,这意味着||运算符在第二个&amp;&amp;运算符之前被执行。这意味着左 - 到 - &amp;&amp;和||的正确执行(不是&amp;&amp;&amp;&quot; precedence)。“

不完全。

(xx && yy || zz && qq)

会像这样评估:

  1. 检查第一个操作员。
  2. 评估xx && yy
  3. 检查下一位操作员。
  4. 如果下一个运算符是||,并且该语句的第一部分为真,则跳过其余部分。
  5. 否则,请在||之后检查下一位运营商,并对其进行评估:zz && qq
  6. 最后,评估||
  7. 根据我的理解,C ++的设计是为了在开始评估之前读取内容。毕竟,在我们的示例中,它不知道我们在&&之后进行了第二次||检查,直到它将其读入,这意味着它必须在||之前读取它到达第二个&&。因此,如果第一部分评估为true,它将不会在||之后执行该部分,但如果第一部分评估为false,那么它将执行第一部分,读入{{1找到并评估第二部分,并使用第二部分的结果来确定最终结果。

答案 6 :(得分:1)

关于你的编辑:不会评估infiniteLoop()因为true || (无论如何)总是如此。使用true | (无论如何)如果应该执行什么。

答案 7 :(得分:1)

关于true && true || infiniteLoop() && infiniteLoop()示例,由于两个特征的组合,两个无限循环调用都没有被评估:&amp;&amp;优先于||和||当左侧为真时短路。

如果&amp;&amp;和||具有相同的优先级,评估必须如下:

((( true && true ) || infiniteLoop ) && infiniteLoop )
(( true || infiniteLoop ) && infiniteLoop )
=> first call to infiniteLoop is short-circuited
(true && infiniteLoop) => second call to infiniteLoop would have to be evaluated

但由于&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;'s&amp;'s的优先权,评估实际上是

(( true && true ) || ( infiniteLoop && infiniteLoop ))
( true || ( infiniteLoop && infiniteLoop ))
=> the entire ( infiniteLoop && infiniteLoop ) expression is short circuited
( true )

答案 8 :(得分:1)

关于安德鲁的最新代码,

#include <iostream>
using namespace std;

bool infiniteLoop () {
    while (true);
    return false;
}

int main() {
    cout << (true && true || infiniteLoop() && infiniteLoop()) << endl; // true
}

短路评估意味着保证不会执行对infiniteLoop的调用。

然而,它以一种不正常的方式很有趣,因为C ++ 0x草案使无限循环 - 没有做任何未定义行为。这条新规则通常被认为是非常不受欢迎和愚蠢的,甚至是彻头彻尾的危险,但它有点潜入选秀。部分来自线程场景的考虑,一篇论文的作者认为它会简化某些事情的规则 - 或者其他相当不相关的事情。

因此,如果编译器位于C ++ 0x-conformance的“前沿”,那么即使它执行了对infiniteLoop的调用,程序也可以终止某些结果。 !当然,使用这样的编译器,它也可能产生可怕的现象,鼻子守护进程......

令人高兴的是,如上所述,短路评估意味着保证不会执行呼叫。

干杯&amp;第h。,

答案 9 :(得分:1)

因为和/或/ true / false非常类似于* / + / 1/0(它们在数学上等同于ish),所以也是如此:

1 * 1 + 0 * 0 == 1

而且很容易记住...

所以是的,它与优先级短路有关。如果将布局操作映射到相应的整数操作,则对布尔操作的优先级相当容易。

答案 10 :(得分:0)

这是一个顺序说明:

  (true && true || false && false)
= ((true && true) || (false && false))  // because && is higher precedence than ||, 
                                        //   like 1 + 2 * 3 = 7  (* higher than +)
= ((true) || (false))
= true

但请注意,如果是

(true || ( ... ))

然后右侧未被评估,因此没有调用任何函数,表达式将只返回true

答案 11 :(得分:-1)

简单的答案是&amp;&amp;优先级高于||。此外,代码不会被执行,因为它不需要知道布尔表达式的结果。是的,它是一个编译器优化。