【问题标题】:Why adding bracket in If statements with Multiple AND OR gives different result?为什么在带有多个 AND OR 的 If 语句中添加括号会产生不同的结果?
【发布时间】:2019-11-23 19:04:04
【问题描述】:

我有一个简单的程序,它有 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。为什么会这样?

【问题讨论】:

    标签: c++ if-statement logical-operators


    【解决方案1】:

    这是因为逻辑与运算符 (&amp;&amp;) 的 precedence 比逻辑或运算符 (||) 高,而逻辑否定运算符 (!) 的优先级在三者中最高。

    这意味着表达式!a &amp;&amp; b || c || d 被分组为((((!a) &amp;&amp; b) || c) || d)。由内而外的工作:

    • !afalse -> (((false &amp;&amp; b) || c) || d)
    • false &amp;&amp; bfalse -> ((false || c) || d)
    • false || ctrue -> (true || d)
    • true || dtrue -> true

    所以整个表达式的计算结果为true

    【讨论】:

    • 呃,好久不见,忘记检查优先级表了。我想起了 && 和 ||具有相同的优先级。感谢详细解释
    • @gameon67 即使它们具有相同的优先级,它仍然会从左到右进行评估,因此您的结果将保持不变。
    • 是的,我做了很糟糕的假设,我认为如果第一个 AND 操作给出 false,那么它会立即破坏 if 语句。
    【解决方案2】:

    &amp;&amp; 运算符的优先级高于 C++(以及大多数其他编程语言)中的 ||。所以,你的第一个版本的代码实际上就像你写的那样执行:

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

    当然,if 语句作为 true 传递,因为 cd 在开始时都设置为 true

    【讨论】:

      【解决方案3】:

      运算符优先级,您可以在此处看到:https://en.cppreference.com/w/cpp/language/operator_precedence 表示 && 将在 || 之前进行评估。

      【讨论】:

        【解决方案4】:

        蒂姆和迈尔斯有正确的答案,你应该接受其中一个。

        我还想在这里解释一个编程概念,如果您打算为工作编写代码,这一点很重要。

        理解运算符优先级非常重要,但您可能不想在代码出现异常时尝试用铅笔检查所有代码。出于这个原因,非常明确地编写代码是有帮助的。我会,而不是你写的,做这样的事情:

        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";
        } 
        

        更长的写作时间?是的。更长的阅读时间?可能是。更长时间了解你在做什么?不,绝对不是。尤其是从现在开始的 2 个月后,当您尝试调试一个棘手的条件时,并且不记得为什么您有那么长的逻辑字符串。

        使用 cmets 效果会更好:

        // 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";
        } 
        

        致那些抱怨执行效率的人:编译器可以通过内联处理大部分优化。如果没有,我会说“先让它工作,然后当你发现问题时,让它工作得更快”。毕竟, “Premature optimization is the root of all evil (or at least of most of it) in programming”。

        【讨论】:

        • 这个简单的逻辑看起来有点矫枉过正,但实际上这是一个非常重要的技巧,对于初学者成为一名专业程序员非常有用
        • 同意@gameon67 -- 但是如果你有过度杀戮的习惯,那么费劲的逻辑就会变得简单。
        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-10-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多