When you combine and and or operators the or operators take precedence meaning their Boolean values are evaluated firs?

The precedence and associativity of C operators affect the grouping and evaluation of operands in expressions. An operator's precedence is meaningful only if other operators with higher or lower precedence are present. Expressions with higher-precedence operators are evaluated first. Precedence can also be described by the word "binding." Operators with a higher precedence are said to have tighter binding.

The following table summarizes the precedence and associativity (the order in which the operands are evaluated) of C operators, listing them in order of precedence from highest to lowest. Where several operators appear together, they have equal precedence and are evaluated according to their associativity. The operators in the table are described in the sections beginning with Postfix Operators. The rest of this section gives general information about precedence and associativity.

Precedence and associativity of C operators

Symbol 1 Type of operation Associativity
[ ] ( ) . ->
++ -- (postfix)
Expression Left to right
sizeof & * + - ~ !
++ -- (prefix)
Unary Right to left
typecasts Unary Right to left
* / % Multiplicative Left to right
+ - Additive Left to right
<< >> Bitwise shift Left to right
< > <= >= Relational Left to right
== != Equality Left to right
& Bitwise-AND Left to right
^ Bitwise-exclusive-OR Left to right
| Bitwise-inclusive-OR Left to right
&& Logical-AND Left to right
|| Logical-OR Left to right
? : Conditional-expression Right to left
= *= /= %=
+= -= <<= >>= &=
^= |=
Simple and compound assignment 2 Right to left
, Sequential evaluation Left to right

1 Operators are listed in descending order of precedence. If several operators appear on the same line or in a group, they have equal precedence.

2 All simple and compound-assignment operators have equal precedence.

An expression can contain several operators with equal precedence. When several such operators appear at the same level in an expression, evaluation proceeds according to the associativity of the operator, either from right to left or from left to right. The direction of evaluation does not affect the results of expressions that include more than one multiplication (*), addition (+), or binary-bitwise (&, |, or ^) operator at the same level. Order of operations is not defined by the language. The compiler is free to evaluate such expressions in any order, if the compiler can guarantee a consistent result.

Only the sequential-evaluation (,), logical-AND (&&), logical-OR (||), conditional-expression (? :), and function-call operators constitute sequence points, and therefore guarantee a particular order of evaluation for their operands. The function-call operator is the set of parentheses following the function identifier. The sequential-evaluation operator (,) is guaranteed to evaluate its operands from left to right. (The comma operator in a function call is not the same as the sequential-evaluation operator and does not provide any such guarantee.) For more information, see Sequence points.

Logical operators also guarantee evaluation of their operands from left to right. However, they evaluate the smallest number of operands needed to determine the result of the expression. This is called "short-circuit" evaluation. Thus, some operands of the expression may not be evaluated. For example, in the expression

x && y++

the second operand, y++, is evaluated only if x is true (nonzero). Thus, y is not incremented if x is false (0).

Examples

The following list shows how the compiler automatically binds several sample expressions:

Expression Automatic Binding
a & b || c (a & b) || c
a = b || c a = (b || c)
q && r || s-- (q && r) || s--

In the first expression, the bitwise-AND operator (&) has higher precedence than the logical-OR operator (||), so a & b forms the first operand of the logical-OR operation.

In the second expression, the logical-OR operator (||) has higher precedence than the simple-assignment operator (=), so b || c is grouped as the right-hand operand in the assignment. Note that the value assigned to a is either 0 or 1.

The third expression shows a correctly formed expression that may produce an unexpected result. The logical-AND operator (&&) has higher precedence than the logical-OR operator (||), so q && r is grouped as an operand. Since the logical operators guarantee evaluation of operands from left to right, q && r is evaluated before s--. However, if q && r evaluates to a nonzero value, s-- is not evaluated, and s is not decremented. If not decrementing s would cause a problem in your program, s-- should appear as the first operand of the expression, or s should be decremented in a separate operation.

The following expression is illegal and produces a diagnostic message at compile time:

Illegal Expression Default Grouping
p == 0 ? p += 1: p += 2 ( p == 0 ? p += 1 : p ) += 2

In this expression, the equality operator (==) has the highest precedence, so p == 0 is grouped as an operand. The conditional-expression operator (? :) has the next-highest precedence. Its first operand is p == 0, and its second operand is p += 1. However, the last operand of the conditional-expression operator is considered to be p rather than p += 2, since this occurrence of p binds more closely to the conditional-expression operator than it does to the compound-assignment operator. A syntax error occurs because += 2 does not have a left-hand operand. You should use parentheses to prevent errors of this kind and produce more readable code. For example, you could use parentheses as shown below to correct and clarify the preceding example:

( p == 0 ) ? ( p += 1 ) : ( p += 2 )

See also

C operators

You have seen that when expressions mix && with || that evaluation must be done in the correct order. Parentheses can be used to group operands with their correct operator, just like in arithmetic. Also like arithmetic operators, logical operators have precedence that determines how things are grouped in the absence of parentheses.

In an expression, the operator with the highest precedence is grouped with its operand(s) first, then the next highest operator will be grouped with its operands, and so on. If there are several logical operators of the same precedence, they will be examined left to right.

It is common for programmers to use parentheses to group operands together for readability even when operator precedence alone would work.

When you combine and and or operators the or operators take precedence meaning their Boolean values are evaluated firs?

Source

Consider an expression describable by the representation below, where both OP1 and OP2 are fill-in-the-blanks for OPerators.

a OP1 b OP2 c

The combination above has two possible interpretations:

(a OP1 b) OP2 c a OP1 (b OP2 c)

Which one the language decides to adopt depends on the identity of OP1 ad OP2.

If OP1 and OP2 have different precedence levels (see the table below), the operator with the higher precedence goes first and associativity does not matter. Observe how multiplication has higher precedence than addition and executed first, even though addition is written first in the code.

console.log(3 + 10 * 2); console.log(3 + (10 * 2)); console.log((3 + 10) * 2);

Within operators of the same precedence, the language groups them by associativity. Left-associativity (left-to-right) means that it is interpreted as (a OP1 b) OP2 c, while right-associativity (right-to-left) means it is interpreted as a OP1 (b OP2 c). Assignment operators are right-associative, so you can write:

with the expected result that a and b get the value 5. This is because the assignment operator returns the value that is assigned. First, b is set to 5. Then the a is also set to 5 — the return value of b = 5, a.k.a. right operand of the assignment.

As another example, the unique exponentiation operator has right-associativity, whereas other arithmetic operators have left-associativity.

const a = 4 ** 3 ** 2; const b = 4 / 3 / 2;

Operators are first grouped by precedence, and then, for adjacent operators that have the same precedence, by associativity. So, when mixing division and exponentiation, the exponentiation always comes before the division. For example, 2 ** 3 / 3 ** 2 results in 0.8888888888888888 because it is the same as (2 ** 3) / (3 ** 2).

For prefix unary operators, suppose we have the following pattern:

OP1 a OP2 b

where OP1 is a prefix unary operator and OP2 is a binary operator. If OP1 has higher precedence than OP2, then it would be grouped as (OP1 a) OP2 b; otherwise, it would be OP1 (a OP2 b).

const a = 1; const b = 2; typeof a + b;

If the unary operator is on the second operand:

a OP2 OP1 b

Then the binary operator OP2 must have lower precedence than the unary operator OP1 for it to be grouped as a OP2 (OP1 b). For example, the following is invalid:

function* foo() { a + yield 1; }

Because + has higher precedence than yield, this would become (a + yield) 1 — but because yield is a reserved word in generator functions, this would be a syntax error. Luckily, most unary operators have higher precedence than binary operators and do not suffer from this pitfall.

If we have two prefix unary operators:

OP1 OP2 a

Then the unary operator closer to the operand, OP2, must have higher precedence than OP1 for it to be grouped as OP1 (OP2 a). It's possible to get it the other way and end up with (OP1 OP2) a:

async function* foo() { await yield 1; }

Because await has higher precedence than yield, this would become (await yield) 1, which is awaiting an identifier called yield, and a syntax error. Similarly, if you have new !A;, because ! has lower precedence than new, this would become (new !) A, which is obviously invalid. (This code looks nonsensical to write anyway, since !A always produces a boolean, not a constructor function.)

For postfix unary operators (namely, ++ and --), the same rules apply. Luckily, both operators have higher precedence than any binary operator, so the grouping is always what you would expect. Moreover, because ++ evaluates to a value, not a reference, you can't chain multiple increments together either, as you may do in C.

Operator precedence will be handled recursively. For example, consider this expression:

First, we group operators with different precedence by decreasing levels of precedence.

  1. The ** operator has the highest precedence, so it's grouped first.
  2. Looking around the ** expression, it has * on the right and + on the right. * has higher precedence, so it's grouped first. * and / have the same precedence, so we group them together for now.
  3. Looking around the *// expression grouped in 2, because + has higher precedence than >>, the former is grouped.

(1 + ( (2 ** 3) * 4 / 5) ) >> 6

Within the *// group, because they are both left-associative, the left operand would be grouped.

(1 + ( ( (2 ** 3) * 4 ) / 5) ) >> 6

Note that operator precedence and associativity only affect the order of evaluation of operators (the implicit grouping), but not the order of evaluation of operands. The operands are always evaluated from left-to-right. The higher-precedence expressions are always evaluated first, and their results are then composed according to the order of operator precedence.

function echo(name, num) { console.log(`Evaluating the ${name} side`); return num; } console.log(echo("left", 4) ** echo("middle", 3) ** echo("right", 2)); console.log(echo("left", 4) / echo("middle", 3) ** echo("right", 2));

If you are familiar with binary trees, think about it as a post-order traversal.

/ ┌────────┴────────┐ echo("left", 4) ** ┌────────┴────────┐ echo("middle", 3) echo("right", 2)

After all operators have been properly grouped, the binary operators would form a binary tree. Evaluation starts from the outermost group — which is the operator with the lowest precedence (/ in this case). The left operand of this operator is first evaluated, which may be composed of higher-precedence operators (such as a call expression echo("left", 4)). After the left operand has been evaluated, the right operand is evaluated in the same fashion. Therefore, all leaf nodes — the echo() calls — would be visited left-to-right, regardless of the precedence of operators joining them.