Coming Soon
This lesson is currently being developed
Operator precedence and associativity
Learn the order in which operators are evaluated.
What to Expect
Comprehensive explanations with practical examples
Interactive coding exercises to practice concepts
Knowledge quiz to test your understanding
Step-by-step guidance for beginners
Development Status
Content is being carefully crafted to provide the best learning experience
Preview
Early Preview Content
This content is still being developed and may change before publication.
6.1 — Operator precedence and associativity
In this lesson, you'll learn how C++ determines the order in which operators are evaluated in complex expressions, understand the difference between precedence and associativity, and master the rules that govern expression evaluation.
What is operator precedence?
Operator precedence determines which operations are performed first when multiple operators appear in the same expression. Just like in mathematics, multiplication and division are performed before addition and subtraction.
Think of precedence as a hierarchy - operators with higher precedence are evaluated before operators with lower precedence.
Consider this mathematical expression: 2 + 3 * 4
Do we calculate (2 + 3) * 4 = 20
or 2 + (3 * 4) = 14
?
In mathematics (and C++), multiplication has higher precedence than addition, so we get 2 + (3 * 4) = 14
.
Operator precedence in action
Let's see how precedence affects C++ expressions:
Basic arithmetic precedence
#include <iostream>
int main()
{
// Multiplication has higher precedence than addition
int result1 = 2 + 3 * 4; // Evaluated as: 2 + (3 * 4) = 14
// Division has higher precedence than subtraction
int result2 = 10 - 8 / 2; // Evaluated as: 10 - (8 / 2) = 6
// Multiple high-precedence operators
int result3 = 2 + 3 * 4 / 2; // Evaluated as: 2 + ((3 * 4) / 2) = 8
std::cout << "2 + 3 * 4 = " << result1 << std::endl;
std::cout << "10 - 8 / 2 = " << result2 << std::endl;
std::cout << "2 + 3 * 4 / 2 = " << result3 << std::endl;
return 0;
}
Output:
2 + 3 * 4 = 14
10 - 8 / 2 = 6
2 + 3 * 4 / 2 = 8
Precedence with different operator types
#include <iostream>
int main()
{
int x = 5;
int y = 3;
// Comparison operators have lower precedence than arithmetic
bool result1 = x + y > 7; // Evaluated as: (x + y) > 7 = true
bool result2 = x * y == 15; // Evaluated as: (x * y) == 15 = true
bool result3 = x > y + 1; // Evaluated as: x > (y + 1) = true
std::cout << "x + y > 7: " << result1 << std::endl;
std::cout << "x * y == 15: " << result2 << std::endl;
std::cout << "x > y + 1: " << result3 << std::endl;
return 0;
}
Output:
x + y > 7: 1
x * y == 15: 1
x > y + 1: 1
What is associativity?
Associativity determines the order of evaluation when operators of the same precedence appear in sequence. It answers: "Do we evaluate from left to right or right to left?"
There are three types of associativity:
- Left-to-right: Operations are performed from left to right
- Right-to-left: Operations are performed from right to left
- No associativity: Cannot be chained (compiler error)
Left-to-right associativity
Most operators associate left-to-right:
#include <iostream>
int main()
{
// Addition and subtraction associate left-to-right
int result1 = 10 - 3 + 2; // Evaluated as: (10 - 3) + 2 = 9
// Multiplication and division associate left-to-right
int result2 = 12 / 3 * 2; // Evaluated as: (12 / 3) * 2 = 8
// Mixed operations with same precedence
int result3 = 20 / 4 * 3 / 2; // Evaluated as: (((20 / 4) * 3) / 2) = 7
std::cout << "10 - 3 + 2 = " << result1 << std::endl;
std::cout << "12 / 3 * 2 = " << result2 << std::endl;
std::cout << "20 / 4 * 3 / 2 = " << result3 << std::endl;
return 0;
}
Output:
10 - 3 + 2 = 9
12 / 3 * 2 = 8
20 / 4 * 3 / 2 = 7
Right-to-left associativity
Some operators associate right-to-left:
#include <iostream>
int main()
{
int a, b, c;
// Assignment operators associate right-to-left
a = b = c = 10; // Evaluated as: a = (b = (c = 10))
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
std::cout << "c = " << c << std::endl;
// Compound assignment with right-to-left associativity
int x = 5;
int y = 3;
x += y += 2; // Evaluated as: x += (y += 2)
// y becomes 5, then x becomes 10
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
return 0;
}
Output:
a = 10
b = 10
c = 10
x = 10
y = 5
C++ operator precedence table
Here's a comprehensive precedence table (from highest to lowest precedence):
Precedence | Operator | Description | Associativity |
---|---|---|---|
1 (highest) | () [] -> . |
Function calls, subscript, member access | Left-to-right |
2 | ++ -- + - ! ~ |
Unary operators | Right-to-left |
3 | * / % |
Multiplicative | Left-to-right |
4 | + - |
Additive | Left-to-right |
5 | << >> |
Bitwise shift | Left-to-right |
6 | < <= > >= |
Relational | Left-to-right |
7 | == != |
Equality | Left-to-right |
8 | & |
Bitwise AND | Left-to-right |
9 | ^ |
Bitwise XOR | Left-to-right |
10 | ` | ` | Bitwise OR |
11 | && |
Logical AND | Left-to-right |
12 | ` | ` | |
13 | ?: |
Ternary conditional | Right-to-left |
14 | = += -= etc. |
Assignment | Right-to-left |
15 (lowest) | , |
Comma | Left-to-right |
Complex precedence example
#include <iostream>
int main()
{
int a = 2, b = 3, c = 4, d = 5;
// Complex expression with multiple precedence levels
bool result = a + b * c > d && c - a == b;
// Let's break down the evaluation step by step:
// 1. b * c = 3 * 4 = 12 (multiplication first)
// 2. a + (b * c) = 2 + 12 = 14 (addition next)
// 3. c - a = 4 - 2 = 2 (subtraction, same level as addition)
// 4. (a + b * c) > d = 14 > 5 = true (relational comparison)
// 5. (c - a) == b = 2 == 3 = false (equality comparison)
// 6. true && false = false (logical AND last)
std::cout << "Complex expression result: " << result << std::endl;
// Verify our step-by-step evaluation
int step1 = b * c;
int step2 = a + step1;
int step3 = c - a;
bool step4 = step2 > d;
bool step5 = step3 == b;
bool step6 = step4 && step5;
std::cout << "Step-by-step verification:" << std::endl;
std::cout << "b * c = " << step1 << std::endl;
std::cout << "a + (b * c) = " << step2 << std::endl;
std::cout << "c - a = " << step3 << std::endl;
std::cout << "(a + b * c) > d = " << step4 << std::endl;
std::cout << "(c - a) == b = " << step5 << std::endl;
std::cout << "Final result = " << step6 << std::endl;
return 0;
}
Output:
Complex expression result: 0
Step-by-step verification:
b * c = 12
a + (b * c) = 14
c - a = 2
(a + b * c) > d = 1
(c - a) == b = 0
Final result = 0
Using parentheses to override precedence
Parentheses have the highest precedence and can override the default order of operations:
Parentheses for clarity and control
#include <iostream>
int main()
{
// Without parentheses - default precedence
int result1 = 2 + 3 * 4; // = 14
// With parentheses - forced order
int result2 = (2 + 3) * 4; // = 20
// Multiple levels of parentheses
int result3 = ((2 + 3) * 4) / (5 - 3); // = 10
std::cout << "2 + 3 * 4 = " << result1 << std::endl;
std::cout << "(2 + 3) * 4 = " << result2 << std::endl;
std::cout << "((2 + 3) * 4) / (5 - 3) = " << result3 << std::endl;
// Parentheses for readability
int x = 10, y = 5, z = 2;
// Hard to read without parentheses
bool complex1 = x > y && y > z || x == y + z;
// Much clearer with parentheses
bool complex2 = (x > y) && (y > z) || (x == (y + z));
std::cout << "Complex expression 1: " << complex1 << std::endl;
std::cout << "Complex expression 2: " << complex2 << std::endl;
return 0;
}
Output:
2 + 3 * 4 = 14
(2 + 3) * 4 = 20
((2 + 3) * 4) / (5 - 3) = 10
Complex expression 1: 1
Complex expression 2: 1
Nested parentheses
#include <iostream>
int main()
{
// Deeply nested expression
int result = ((5 + 3) * (4 - 1)) / ((6 / 2) + 1);
// Breaking it down:
// (5 + 3) = 8
// (4 - 1) = 3
// (6 / 2) = 3
// 8 * 3 = 24
// 3 + 1 = 4
// 24 / 4 = 6
std::cout << "Complex nested result: " << result << std::endl;
// Step by step for verification
int inner1 = 5 + 3; // 8
int inner2 = 4 - 1; // 3
int inner3 = 6 / 2; // 3
int numerator = inner1 * inner2; // 24
int denominator = inner3 + 1; // 4
int final = numerator / denominator; // 6
std::cout << "Step by step: " << inner1 << " * " << inner2
<< " / (" << inner3 << " + 1) = " << final << std::endl;
return 0;
}
Output:
Complex nested result: 6
Step by step: 8 * 3 / (3 + 1) = 6
Common precedence mistakes and how to avoid them
Mistake 1: Mixing arithmetic and comparison operators
#include <iostream>
int main()
{
int score = 85;
int passing = 60;
// ❌ Confusing expression - what does this mean?
// bool isPassing = score > passing + 10;
// Is this: (score > passing) + 10 or score > (passing + 10)?
// ✅ Clear with parentheses
bool isExcellent = score > (passing + 10); // score > 70
bool isAboveAverage = (score > passing) && (score < 90);
std::cout << "Score: " << score << std::endl;
std::cout << "Excellent (>70): " << isExcellent << std::endl;
std::cout << "Above average (60-90): " << isAboveAverage << std::endl;
return 0;
}
Output:
Score: 85
Excellent (>70): 1
Above average (60-90): 1
Mistake 2: Assignment vs. equality in conditions
#include <iostream>
int main()
{
int x = 5;
// ❌ Common mistake - assignment instead of comparison
// if (x = 10) // This assigns 10 to x, then checks if 10 is true (it is)
// ✅ Correct comparison
if (x == 10) {
std::cout << "x equals 10" << std::endl;
} else {
std::cout << "x does not equal 10 (x = " << x << ")" << std::endl;
}
// Demonstrating the assignment mistake
int y = 5;
if (y = 10) { // Assignment! y becomes 10, condition is true
std::cout << "This will always execute! y is now: " << y << std::endl;
}
return 0;
}
Output:
x does not equal 10 (x = 5)
This will always execute! y is now: 10
Mistake 3: Logical operator precedence
#include <iostream>
int main()
{
bool a = true;
bool b = false;
bool c = true;
// ❌ Unclear intention
// bool result = a || b && c; // What's the intention here?
// This evaluates as: a || (b && c) because && has higher precedence than ||
bool result1 = a || b && c; // true || (false && true) = true
// ✅ Be explicit about your intention
bool result2 = (a || b) && c; // (true || false) && true = true
bool result3 = a || (b && c); // true || (false && true) = true
std::cout << "a || b && c = " << result1 << std::endl;
std::cout << "(a || b) && c = " << result2 << std::endl;
std::cout << "a || (b && c) = " << result3 << std::endl;
return 0;
}
Output:
a || b && c = 1
(a || b) && c = 1
a || (b && c) = 1
Best practices for precedence and associativity
1. Use parentheses for clarity
// ❌ Hard to read
int result = a + b * c / d - e % f;
// ✅ Clear intent
int result = a + ((b * c) / d) - (e % f);
2. Break complex expressions into steps
#include <iostream>
int main()
{
int a = 10, b = 5, c = 3, d = 2;
// ❌ Complex one-liner
int complex = (a + b) * c / d + a % c - b / d;
// ✅ Broken into clear steps
int sum = a + b; // 15
int product = sum * c; // 45
int division1 = product / d; // 22
int remainder = a % c; // 1
int division2 = b / d; // 2
int result = division1 + remainder - division2; // 21
std::cout << "Complex result: " << complex << std::endl;
std::cout << "Step-by-step result: " << result << std::endl;
return 0;
}
Output:
Complex result: 21
Step-by-step result: 21
3. Remember the most important precedence rules
- Parentheses always come first
- Multiplication and division before addition and subtraction
- Arithmetic before comparisons
- Comparisons before logical operations
- Assignment comes last
4. When in doubt, add parentheses
// If you're not sure about precedence, parentheses never hurt
int result = ((a + b) * c) / ((d - e) + f);
Summary
Operator precedence and associativity control how C++ evaluates complex expressions:
Precedence determines which operators are evaluated first:
- Higher precedence operators are evaluated before lower precedence operators
- Multiplication/division before addition/subtraction
- Arithmetic before comparisons, comparisons before logical operations
Associativity determines evaluation order for same-precedence operators:
- Most operators associate left-to-right
- Assignment and ternary operators associate right-to-left
Key practices:
- Use parentheses to make your intentions clear
- Break complex expressions into simpler steps
- Learn the most common precedence relationships
- When in doubt, use parentheses rather than relying on precedence rules
Understanding precedence and associativity helps you write correct expressions and debug problems where operations aren't happening in the order you expected.
Quiz
-
What is the result of
2 + 3 * 4 - 1
? a) 19 b) 13 c) 18 d) 17 -
How does
x = y = z = 5
get evaluated? a)(x = y) = (z = 5)
b)x = (y = (z = 5))
c) Left to right d) Undefined -
What is the result of
10 - 6 / 2 + 1
? a) 3 b) 8 c) 2 d) 9 -
Which operators have higher precedence than addition (
+
)? a) Multiplication and division b) Comparison operators c) Logical AND d) Assignment -
What associativity do most arithmetic operators have? a) Right-to-left b) Left-to-right c) No associativity d) Context-dependent
Practice exercises
Try these exercises to master precedence and associativity:
-
Expression Evaluator: Write a program that evaluates complex expressions step-by-step, showing how precedence affects the result.
-
Precedence Comparison: Create expressions that produce different results depending on where you place parentheses.
-
Bug Hunter: Find and fix precedence-related bugs in expressions that don't evaluate as intended.
-
Calculator Logic: Build a simple expression parser that respects C++ precedence rules.
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions