- Skip to main content
- Skip to search
- Skip to select language
- Sign up for free
- Remember language
- Português (do Brasil)
Operator precedence
Operator precedence determines how operators are parsed concerning each other. Operators with higher precedence become the operands of operators with lower precedence.
Precedence and associativity
Consider an expression describable by the representation below, where both OP1 and OP2 are fill-in-the-blanks for OPerators.
The combination above has two possible interpretations:
Which one the language decides to adopt depends on the identity of OP1 and 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.
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.
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:
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) .
If the unary operator is on the second operand:
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:
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:
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 :
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.
- The ** operator has the highest precedence, so it's grouped first.
- Looking around the ** expression, it has * on the right and + on the left. * has higher precedence, so it's grouped first. * and / have the same precedence, so we group them together for now.
- Looking around the * / / expression grouped in 2, because + has higher precedence than >> , the former is grouped.
Within the * / / group, because they are both left-associative, the left operand would be grouped.
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.
If you are familiar with binary trees, think about it as a post-order traversal .
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.
Short-circuiting
In the previous section, we said "the higher-precedence expressions are always evaluated first" — this is generally true, but it has to be amended with the acknowledgement of short-circuiting , in which case an operand may not be evaluated at all.
Short-circuiting is jargon for conditional evaluation. For example, in the expression a && (b + c) , if a is falsy , then the sub-expression (b + c) will not even get evaluated, even if it is grouped and therefore has higher precedence than && . We could say that the logical AND operator ( && ) is "short-circuited". Along with logical AND, other short-circuited operators include logical OR ( || ), nullish coalescing ( ?? ), and optional chaining ( ?. ).
When evaluating a short-circuited operator, the left operand is always evaluated. The right operand will only be evaluated if the left operand cannot determine the result of the operation.
Note: The behavior of short-circuiting is baked in these operators. Other operators would always evaluate both operands, regardless if that's actually useful — for example, NaN * foo() will always call foo , even when the result would never be something other than NaN .
The previous model of a post-order traversal still stands. However, after the left subtree of a short-circuiting operator has been visited, the language will decide if the right operand needs to be evaluated. If not (for example, because the left operand of || is already truthy), the result is directly returned without visiting the right subtree.
Consider this case:
Only C() is evaluated, despite && having higher precedence. This does not mean that || has higher precedence in this case — it's exactly because (B() && A()) has higher precedence that causes it to be neglected as a whole. If it's re-arranged as:
Then the short-circuiting effect of && would only prevent C() from being evaluated, but because A() && C() as a whole is false , B() would still be evaluated.
However, note that short-circuiting does not change the final evaluation outcome. It only affects the evaluation of operands , not how operators are grouped — if evaluation of operands doesn't have side effects (for example, logging to the console, assigning to variables, throwing an error), short-circuiting would not be observable at all.
The assignment counterparts of these operators ( &&= , ||= , ??= ) are short-circuited as well. They are short-circuited in a way that the assignment does not happen at all.
The following table lists operators in order from highest precedence (18) to lowest precedence (1).
Several general notes about the table:
- Not all syntax included here are "operators" in the strict sense. For example, spread ... and arrow => are typically not regarded as operators. However, we still included them to show how tightly they bind compared to other operators/expressions.
- Some operators have certain operands that require expressions narrower than those produced by higher-precedence operators. For example, the right-hand side of member access . (precedence 17) must be an identifier instead of a grouped expression. The left-hand side of arrow => (precedence 2) must be an arguments list or a single identifier instead of some random expression.
- Some operators have certain operands that accept expressions wider than those produced by higher-precedence operators. For example, the bracket-enclosed expression of bracket notation [ … ] (precedence 17) can be any expression, even comma (precedence 1) joined ones. These operators act as if that operand is "automatically grouped". In this case we will omit the associativity.
- The operand can be any expression.
- The "right-hand side" must be an identifier.
- The "right-hand side" can be any expression.
- The "right-hand side" is a comma-separated list of any expression with precedence > 1 (i.e. not comma expressions). The constructor of a new expression cannot be an optional chain.
- The operand must be a valid assignment target (identifier or property access). Its precedence means new Foo++ is (new Foo)++ (a syntax error) and not new (Foo++) (a TypeError: (Foo++) is not a constructor).
- The operand must be a valid assignment target (identifier or property access).
- The operand cannot be an identifier or a private property access.
- The left-hand side cannot have precedence 14.
- The operands cannot be a logical OR || or logical AND && operator without grouping.
- The "left-hand side" must be a valid assignment target (identifier or property access).
- The associativity means the two expressions after ? are implicitly grouped.
- The "left-hand side" is a single identifier or a parenthesized parameter list.
- Only valid inside object literals, array literals, or argument lists.
The precedence of groups 17 and 16 may be a bit ambiguous. Here are a few examples to clarify.
- Optional chaining is always substitutable for its respective syntax without optionality (barring a few special cases where optional chaining is forbidden). For example, any place that accepts a?.b also accepts a.b and vice versa, and similarly for a?.() , a() , etc.
- Member expressions and computed member expressions are always substitutable for each other.
- Call expressions and import() expressions are always substitutable for each other.
- The "left-hand side" of a member access can be: a member access ( a.b.c ), new with arguments ( new a().b ), and function call ( a().b ).
- The "left-hand side" of new with arguments can be: a member access ( new a.b() ) and new with arguments ( new new a()() ).
- The "left-hand side" of a function call can be: a member access ( a.b() ), new with arguments ( new a()() ), and function call ( a()() ).
- The operand of new without arguments can be: a member access ( new a.b ), new with arguments ( new new a() ), and new without arguments ( new new a ).
- C++ Data Types
- C++ Input/Output
- C++ Pointers
- C++ Interview Questions
- C++ Programs
- C++ Cheatsheet
- C++ Projects
- C++ Exception Handling
- C++ Memory Management
Operator Precedence and Associativity in C++
In C++, operator precedence and associativity are important concepts that determine the order in which operators are evaluated in an expression. Operator precedence tells the priority of operators, while associativity determines the order of evaluation when multiple operators of the same precedence level are present.
Operator Precedence in C++
In C++, operator precedence specifies the order in which operations are performed within an expression. When an expression contains multiple operators, those with higher precedence are evaluated before those with lower precedence.
For expression:
As, multiplication has higher precedence than subtraction, that's why 17 * 6 is evaluated first, resulting in x = -97 . If we want to evaluate 5 - 17 first, we can use parentheses:
Now 5 - 17 is evaluated first, resulting in x = -72 .
Example of C++ Operator Precedence
Remember that, using parentheses makes code more readable, especially when dealing with complex expressions.
Operator Associativity in C++
Operator associativity determines the order in which operands are grouped when multiple operators have the same precedence. There are two types of associativity:
Left-to-right associativity: In expressions like a + b - c, the addition and subtraction operators are evaluated from left to right. So, (a + b) - c is equivalent.
Right-to-left associativity: Some operators, like the assignment operator =, have right-to-left associativity. For example, a = b = 4; assigns the value of b to a.
As, subtraction is left-associative, that's why 10 - 5 evaluated first, resulting in x = 3 . But in case of multiplication:
Now 3 * 4 is evaluated first, resulting in x = 24 because multiplication is right-associative.
Example of C++ Operator Associativity
Understanding both the precedence and associativity of operators is crucial for writing expressions that produce the desired results.
Operator Precedence Table in C++
The operator precedence table in C++ is a table that lists the operators in order of their precedence level. Operators with higher precedence are evaluated before operators with lower precedence. This table also includes the associativity of the operators, which determines the order in which operators of the same precedence are processed.
The operators are listed from top to bottom, in descending precedence
Similar Reads
- cpp-operator
Please Login to comment...
Improve your coding skills with practice.
What kind of Experience do you want to share?
Learn C practically and Get Certified .
Popular Tutorials
Popular examples, reference materials, certification courses.
Created with over a decade of experience and thousands of feedback.
C Introduction
- Getting Started with C
- Your First C Program
C Fundamentals
- C Variables, Constants and Literals
- C Data Types
- C Input Output (I/O)
C Programming Operators
C Flow Control
C if...else Statement
- C while and do...while Loop
- C break and continue
- C switch Statement
- C goto Statement
- C Functions
- C User-defined functions
- Types of User-defined Functions in C Programming
- C Recursion
- C Storage Class
C Programming Arrays
- C Multidimensional Arrays
- Pass arrays to a function in C
C Programming Pointers
- Relationship Between Arrays and Pointers
- C Pass Addresses and Pointers
- C Dynamic Memory Allocation
- C Array and Pointer Examples
- C Programming Strings
- String Manipulations In C Programming Using Library Functions
- String Examples in C Programming
C Structure and Union
- C structs and Pointers
- C Structure and Function
C Programming Files
- C File Handling
- C Files Examples
C Additional Topics
- C Keywords and Identifiers
C Precedence And Associativity Of Operators
- C Bitwise Operators
- C Preprocessor and Macros
- C Standard Library Functions
C Tutorials
Bitwise Operators in C Programming
- Compute Quotient and Remainder
- Precedence of operators
The precedence of operators determines which operator is executed first if there is more than one operator in an expression.
Let us consider an example:
In C, the precedence of * is higher than - and = . Hence, 17 * 6 is evaluated first. Then the expression involving - is evaluated as the precedence of - is higher than that of = .
Here's a table of operators precedence from higher to lower. The property of associativity will be discussed shortly.
- Operators Precedence & Associativity Table
- Associativity of Operators
The associativity of operators determines the direction in which an expression is evaluated. For example,
Here, the value of a is assigned to b , and not the other way around. It's because the associativity of the = operator is from right to left.
Also, if two operators of the same precedence (priority) are present, associativity determines the direction in which they execute.
Here, operators == and != have the same precedence. And, their associativity is from left to right. Hence, 1 == 2 is executed first.
The expression above is equivalent to:
Note: If a statement has multiple operators, you can use parentheses () to make the code more readable.
Table of Contents
Sorry about that.
Our premium learning platform, created with over a decade of experience and thousands of feedbacks .
Learn and improve your coding skills like never before.
- Interactive Courses
- Certificates
- 2000+ Challenges
COMMENTS
The assignment operator has left-to-right-to-left associativity, which means that the value of the expression to the left of the assignment operator is evaluated first and that the result is assigned to the operand on the right.
The assignment operator _____. a. is a binary operator b. has left-to-right associativity c. is most often represented by a colon d. two of the above
Operator Associativity in Assignment Operators: Assignment operators, like the simple assignment (=) and compound assignments (e.g., +=), typically have right-to-left …
Jul 25, 2024 · 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). …
Left-to-right associativity: In expressions like a + b - c, the addition and subtraction operators are evaluated from left to right. So, (a + b) - c is equivalent. Right-to …
The associativity of operators determines the direction in which an expression is evaluated. For example, b = a; Here, the value of a is assigned to b, and not the other way …
The right-associativity of the = operator allows expressions such as a = b = c to be interpreted as a = (b = c). In C++, the assignment a = b is an expression that evaluates to the same value as …