Binary operators

Pages: 12
I studied this on internet that Binary operator && has higher precedence than ||:
For example, consider the following expression.
a || b && c || d;

// Even though it has higher precedence whole expression is treated as:
a || (b && c || d);

// a as left operand and remaining as right operand

// if 'a' results in true then short-circuit occurs right operand is not evaluated.....

Final answer: (a || (b && c)) || d;

After studying this that if 'a' results in false the whole expression is treated as:
a || (b && c || d);
If 'a' results in false the whole expression should be treated as:
a || ((b && c) || d);
Why it is treated as: a || (b && c || d); ?
Why it is treated as: a || (b && c || d); ?

It isn't. The correct explicit placement of parens is:
 
    ((a || (b && c)) || d)

a || b && c || d The && has higher precedence than ||. Therefore, b && c must be evaluated before the rest.

The && and || are lazy. Therefore, only b has to be evaluated before b && c

1. Evaluate b IF b is false THEN b && c is false ELSE evaluate c

2. Now we know value of b && c, lets call it x

3. Evaluate a IF a is true THEN a || x is true ELSE value of a || x is value of x

4. Lets call value of a || b && c "y"

5. IF y is true THEN return true ELSE evaluate d AND return value of d
Last edited on
The && has higher precedence than ||. Therefore, b && c must be evaluated before the rest.

This is a common misconception.
Precedence is not about "when" things are evaluated.
It's about where the implicit parentheses go.
In this case, a will be evaluated first.
If a is true, then nothing else will be evaluated (due to short-circuit evaluation of the ||).
Only if a is false will b be evaluated.
Then, only if b is true will c be evaluated.
Then, only if c is false will d be evaluated.

It's easy to see that this is the order of evaluation by looking at the syntax tree and considering how it will be evaluated:

                  ||
      ||                   d   
  a        &&
         b    c

We need to evaluate the top ||.
Due to short-circuit evaluation, we must evaluate the left side first (note that if we didn't have short-circuit evaluation, it wouldn't matter which side was done "first" (they could potentially be done in parallel).
The left side of the top || is another ||, so we need to evaluate its left side.
So the first thing we evaluate is a.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;

bool a(bool x) { cout << "a "; return x; }
bool b(bool x) { cout << "b "; return x; }
bool c(bool x) { cout << "c "; return x; }
bool d(bool x) { cout << "d "; return x; }

void f(bool w, bool x, bool y, bool z) {
    cout << w << x << y << z << ": ";
    bool result = a(w) || b(x) && c(y) || d(z);
    cout << '\t' << result << '\n';
}

int main() {
    cout << "abcd\n";
    for (unsigned i = 0; i < 16; ++i)
        f(i >> 3, i >> 2 & 1, i >> 1 & 1, i & 1);
}


abcd
0000: a b d 	0
0001: a b d 	1
0010: a b d 	0
0011: a b d 	1
0100: a b c d 	0
0101: a b c d 	1
0110: a b c 	1
0111: a b c 	1
1000: a 	1
1001: a 	1
1010: a 	1
1011: a 	1
1100: a 	1
1101: a 	1
1110: a 	1
1111: a 	1
Last edited on
Doh!

Thanks.
Precedence is not about "when" things are evaluated.
It's about where the implicit parentheses go.
what does that mean? what are the meanings of implicit here?
The arithmetic operators and logical operators in an expression are evaluated according to their precedence? The precedence means which operator will be evaluated first and which will be evaluated after that and so on?
> The precedence means which operator will be evaluated first and which will be evaluated after that and so on?

No. Precedence and associativity of operators are used at compile time to determine how the operators are bound to their arguments.

For example, with a, b, c and d being of type int, we write: ++a + ++b * ++c + ++d

The increment operator has a higher precedence than multiplicative and additive operators,
so this is parsed as: (++a) + (++b) * (++c) + (++d)

The multiplicative operator has a higher precedence than the additive operator,
so this is parsed as: (++a) + ( (++b) * (++c) ) + (++d)

The additive operator associates from left to right,
so this is parsed as: ( (++a) + ( (++b) * (++c) ) ) + (++d)


Order of evaluation is what happens at runtime when the expression is evaluated.

With ( (++a) + ( (++b) * (++c) ) ) + (++d)
the subexpressions ++b and ++d may be evaluated in any order:
++b before ++d
or ++d before ++b
or the evaluations of ++b and ++d may overlap.
If the same expression is evaluated again, the evaluation order may be different.

More information: https://en.cppreference.com/w/cpp/language/eval_order
Precedence describes where the implicit parentheses go. For example * has higher precedence than +, which means a + b * c means a + (b*c) instead of (a+b) * c

Associativity describes where the implicit parentheses go when the operators are the same (or have the same precedence). For example, - associates left to right, which means a - b - c is interpreted as (a-b) - c) instead of a - (b-c).

Order of evaluation describes the order in which the operands are evaluated. For example, || evaluates left to right, so f() || g() will call f() first and then (if necessary because of short circuit evaluation) call g(). For most operators, the order of evaluation is undefined.

So precedence and associativity describe when it evaluates the operators and order of evaluation describes when it evaluates the operands.
> So precedence and associativity describe when it evaluates the operators
> and order of evaluation describes when it evaluates the operands.

The rules (sequenced-before rules) specify the order of evaluation of parts of an expression;
both operands as well as subexpressions.

For example, with a * b + ++c, the subexpression a * b may be evaluated before the subexpression ++c.
* and ++ are operators; the increment operator has a higher precedence than the multiplicative operator.
Precedence and associativity do not describe when they (the expressions containing them) are evaluated.
>Precedence describes where the implicit parentheses go.
what are the meanings of implicit here?
Where parentheses aren't explicitly specified

eg:

a + b + c

has implicit parentheses:

(a + b) + c

and

a + b * c

has:

a + (b * c)

Stroustrup in PP&P:
you should avoid complicated expressions anyway, and there is a simple rule that can keep you out of trouble:
if you change the value of a variable in an expression, don’t read or write it twice in that same expression.
:)
>Precedence is not about "when" things are evaluated.
I studied this in the book that the precedence means which operator will be evaluated first and which will be evaluated after that and so on. If there is no such rule that the operators with higher precedence will be evaluated first then what is the purpose of studying the precedence of operators?
Last edited on
> If there is no such rule that the operators with higher precedence will be evaluated first
> then what is the purpose of studying the precedence of operators?

We need to know that if we write a + b * c, it would be evaluated as a + (b* c)
(that * has a higher precedence than +)

Whether the run-time evaluation is a first and c later or vice versa is of interest to people who write compilers (optimizers). The precise order of runtime evaluation of the above expression is not of much concern for us; in general, we play safe by following Stroustrup's simple rule.

This may make the example easier for you to understand:
We need to know that if we write f() + g() * h(), it would be evaluated as f() + (g())*h())
(that * has a higher precedence than +)
Whether the run-time evaluation is f() first and h() later or vice versa is of interest to people who write compilers (optimizers). The precise order of runtime evaluation of the above expression is not of much concern for us.
Last edited on
We need to know that if we write a + b * c, it would be evaluated as (a+b) * c
(that * has a higher precedence than +)


a + (b * c)
Thanks! Corrected now.
Keyboards sometimes have a life of their own and don't always capture the keys that we thought we had pressed but something else :)
It was just a careless mistake by me; the keyboard is blameless in this case.
Whether the run-time evaluation is f() first and h() later or vice versa is of interest to people who write compilers (optimizers). The precise order of runtime evaluation of the above expression is not of much concern for us.
JLBorges knows this, but for those reading along, it's important to understand that the language doesn't specify or guarantee the order in which the functions are called. So it's the lack of a defined order that matters to the programmer. If calling f() first changes the value of h(), or vice versa, then the behavior is undefined. In f() + g() * h(), the compiler can generate code to call all three functions in any order. It can be different from one compiler to the next, or even from one expression to the next in the same program with the same compiler. All you know for sure is that the result of g() and h() will be multiplied together and then added to the result of f(). If calling either of these functions can change the result of calling another then the behavior is undefined.
Pages: 12