为什么在多重AND OR的If语句中添加括号会导致不同的结果?

4

我有一个简单的程序,其中包含1个AND运算符和多个OR运算符,如下所示:

#include <iostream>

using namespace std;

int main()
{
    bool a = true;
    bool b = true;
    bool c = true;
    bool d = true;

    if (!a && b || c || d)
        cout << "run";
    else
        cout << "pass";

    return 0;
}

我期望程序将会输出pass,因为我将a声明为true。但是,如果你运行该程序,它将输出:run

如果我更改if语句的行并添加括号

if (!a && (b || c || d))
        cout << "run";
    else
        cout << "pass";

它将会产生期望的输出pass。为什么会这样工作呢?
5个回答

10
这是因为逻辑与运算符(&&)比逻辑或运算符(||)具有更高的优先级,而逻辑非运算符(!)的优先级是三者中最高的。
这意味着表达式 !a && b || c || d 被分组为 ((((!a) && b) || c) || d)。从内向外工作:
- !afalse -> (((false && b) || c) || d) - false && bfalse -> ((false || c) || d) - false || ctrue -> (true || d) - true || dtrue -> true 因此整个表达式计算结果为 true

哎呀,好久没看优先级表了,我忘记了 && 和 || 的优先级是一样的。感谢详细的解释。 - gameon67
1
@gameon67 即使它们具有相同的优先级,它们仍将从左到右进行评估,因此您的结果将保持不变。 - Michael Kolber
是的,我做了可怕的假设,我认为如果第一个AND操作返回false,那么它会立即中断if语句。 - gameon67

4

4
在C++(以及大多数其他编程语言)中,&&运算符比||运算符具有更高的优先级。因此,您的代码的第一个版本实际上执行的时候就像是您写的这样:
if ((!a && b) || c || d)  // if (false || true || true)
    cout << "run";
else
    cout << "pass";

当然,if语句会通过检验,因为在开始时cd 都被设置为true

3

Tim和Miles都有正确的答案,你应该接受其中之一。

我也想在这里解释一个编程概念,如果你计划以后从事编程工作,这个概念非常重要。

理解运算符优先级非常重要,但当代码出现问题时,你可能不想尝试手动检查所有代码。因此,在编写代码时非常明确是很有帮助的。与其像你所写的那样,我会做出类似于下面的写法:

bool should_run(bool a, bool b, bool c, bool d) {
  if( ! a ) {
    return true;
  }
  return b || c || d;
}

if( should_run(a, b, c, d)) {
  cout << "run";
} else {
  cout << "pass";
} 

需要写更长时间吗?是的。需要读更长时间吗?也许。需要更长时间理解你在做什么吗?绝对不需要,特别是两个月后当你试图调试一个棘手的条件时,你不记得为什么有那么长的逻辑字符串。

加上注释会更好:

// returns true if the conditions are right to run,
// otherwise, return false to indicate a pass.
bool should_run(bool a, bool b, bool c, bool d) {
  // if coach said we don't run, then we pass!
  if( ! a ) {
    return true;
  } // coach said pass.

  // if the tight end, halfback, or running back are ready, then run.
  // if all three are not ready, then I guess we're passing.
  return b || c || d;
}

if( should_run(a, b, c, d)) {
  cout << "run";
} else {
  cout << "pass";
} 

对于那些会抱怨执行效率的人:编译器可以通过内联来进行大部分优化。如果不能,我建议“先让它能运行,等到发现问题时再考虑如何让它更快”。毕竟,“过早的优化是程序设计中所有恶之根源(或者至少是大部分)”。

1
这个简单的逻辑看起来有些过度,但实际上这是一个非常重要的技巧,对于初学者来说非常有用,可以帮助他们成为专业程序员。 - gameon67
同意 @gameon67 -- 但如果你习惯于过度设计,那么复杂的逻辑就变得简单了。 - PaulProgrammer

0

操作具有优先级,具有相同优先级值的操作将从左到右依次执行。


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