Precedence, Associativity & Conversions
Who goes first?When an expression has several operators, C needs rules to know which operands belong together:
precedence (which operator binds tighter) and associativity (left to right or right to left).
And when types are mixed, values are converted. In the lab below you watch C add its invisible parentheses,
see conversions keep or lose data, and meet sizeof, ?: and the comma operator.
- a + b * cmeans a + (b * c)
- a - b - cmeans (a - b) - c
- (double) xconverts x on purpose
Ready
Keyboard: ← → step · Space play / pause · R reset · Esc exit classroom mode
The ideas behind the lab
Exactly what you watched happen, in plain steps.
C adds invisible parentheses
Precedence says which operator binds tighter: * before +. Associativity says what happens between operators of the SAME level: most go left to right, but unary operators, ?: and assignments go right to left. Together they decide how C groups an expression — before anything is calculated.
a + b * c → a + (b * c) * binds tighter a - b - c → (a - b) - c left to right a = b = c → a = (b = c) right to left !a == b → (!a) == b unary first a & b == c → a & (b == c) == before & ! x > 0 && y > 0 → (x > 0) && (y > 0)
| Level | Operators | Kind | Associativity |
|---|---|---|---|
| 1 | () [] -> . x++ x-- | call, index, member, postfix | left to right |
| 2 | ++x --x + - ! ~ (type) * & sizeof | unary | right to left |
| 3 | * / % | multiplicative | left to right |
| 4 | + - | additive | left to right |
| 5 | << >> | 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 | left to right |
| 11 | && | logical AND | left to right |
| 12 | || | logical OR | left to right |
| 13 | ?: | conditional | right to left |
| 14 | = += -= *= /= %= &= ^= |= <<= >>= | assignment | right to left |
| 15 | , | comma | left to right |
Precedence and associativity
- Unary operators bind tightest, then * / %, then + −, then shifts, comparisons, bitwise, logical, ?:, assignment, comma.
- Operators of the same level group left to right (a − b − c is (a − b) − c)…
- …except unary operators, ?: and assignments, which group right to left (a = b = c is a = (b = c)).
- Precedence decides GROUPING, not the order of calculation — only &&, ||, ?: and , fix that order.
- Parentheses always win. Use them whenever the reader might hesitate.
Implicit conversions
- Integer promotion: char and short are converted to int before any arithmetic.
- Mixed types: the smaller type is converted to the bigger one (int → long → float → double).
- Assignment converts the value to the type of the variable: it can lose decimals or high bits.
- int mixed with unsigned int becomes unsigned: -1 < 1u is false!
- Widening is safe; narrowing can lose data — gcc -Wall -Wconversion warns.
Casts and special operators
- A cast (type) value converts on purpose: (double) sum / n gives a real division.
- The cast binds tightly: (double) (a / b) converts the already-cut int result.
- sizeof gives a size in bytes (size_t, %zu); its operand is NOT evaluated.
- cond ? x : y evaluates the condition, then only ONE of x and y.
- The comma operator evaluates left to right and keeps the last value.
Grouping and conversions in one program
Every line, explained.
#include <stdio.h>
int main(void)
{
int a = 10, b = 3;
int r1 = a + b * 2;
* first: 10 + 6 = 16.
int r2 = (a + b) * 2;
Parentheses first: 13 * 2 = 26.
int r3 = a - b - 2;
Left to right: (10 − 3) − 2 = 5.
int x, y;
x = y = 4;
Right to left: y = 4 first, and its value (4) is stored in x.
double avg = (double) (a + b) / 2;
The cast converts 13 to 13.0, so the division is real: 6.5.
int big = a > b ? a : b;
The conditional operator picks the larger: 10.
printf("%d %d %d %d %d %.1f %d\n", r1, r2, r3, x, y, avg, big);
Prints 16 26 5 4 4 6.5 10
return 0;
}
Spot the bug
Mistakes almost every beginner makes — and how to fix them.
Bitwise & with ==
if (flags & 4 == 4)
if ((flags & 4) == 4)
== (level 7) binds tighter than & (level 8), so the first means flags & (4 == 4), which is flags & 1.
Shift with +
int r = 1 << n + 1; // 1 << (n + 1)
int r = (1 << n) + 1;
+ binds tighter than <<. Put parentheses around the shift if you mean "shift, then add".
A cast that comes too late
double avg = (double) (sum / n);
double avg = (double) sum / n;
In the first, sum / n is int division and has already lost the decimals before the cast.
Comparing signed and unsigned
int i = -1; if (i < sizeof(int)) // false!
int i = -1; if (i < (int) sizeof(int))
sizeof gives an unsigned value, so i is converted to unsigned: -1 becomes 4294967295. gcc -Wextra warns about signed/unsigned comparisons.
Expecting precedence to set the order of side effects
int r = i++ + i++;
int r = i + (i + 1); i += 2;
Precedence only groups. Changing i twice in one expression is undefined behaviour — the compiler may do it in any order.
Check your understanding
Answer each question — you will see the explanation straight away.
How does C group a + b * c - d ?
* first, then + and − from left to right.
What is 20 / 4 / 5 ?
/ groups left to right: (20 / 4) / 5 = 5 / 5 = 1.
After int a, b; a = b = 7; what are a and b?
Assignment groups right to left: b = 7 first, then a gets that value.
What is the value of (double) 7 / 2 ?
The cast converts 7 to 7.0 first, so the division is real.
What is sizeof(3 + 2.5) on a typical computer?
int + double is a double, which is 8 bytes. The addition is not even done.
Precedence, Associativity & Conversions quiz
Test yourself: 10 questions, 70% to pass. Create a free account to take the quiz, save your progress and work towards the certificate.