C Operators and Their Precedence
|
Tokens |
Operator |
Class |
Precedence |
Associates |
|---|---|---|---|---|
| names, literals | simple tokens |
primary |
17 |
n/a |
| a[k] | subscripting |
postfix |
17 |
left |
| f(...) | function call |
postfix |
17 |
left |
| . | direct selection |
postfix |
17 |
left |
| -> | indirect selection |
postfix |
17 |
left |
| ++ -- | increment, decrement |
postfix |
17 |
left |
| ++ -- | increment, decrement |
prefix |
15 |
right |
| sizeof | size |
unary |
15 |
right |
| ~ | bitwise not |
unary |
15 |
right |
| ! | logical not |
unary |
15 |
right |
| - + | arithmetic negation, plus |
unary |
15 |
right |
| & | address of |
unary |
15 |
right |
| * | indriection |
unary |
15 |
right |
| (type name) | casts |
unary |
14 |
right |
| * / % | multiplicative |
binary |
13 |
left |
| + - | additive |
binary |
12 |
left |
| << >> | left and right shift |
binary |
11 |
left |
| < > <= >= | relational |
binary |
10 |
left |
| == != | equality/inequality |
binary |
9 |
left |
| & | bitwise and |
binary |
8 |
left |
| ^ | bitwise xor |
binary |
7 |
left |
| | | bitwise or |
binary |
6 |
left |
| && | logical and |
binary |
5 |
left |
| || | logical or |
binary |
4 |
left |
| ? : | conditional |
ternary |
3 |
right |
| = += -= *= /= %= <<= >>= &= ^= |= | assignment |
binary |
2 |
right |
| , | sequential evaluation |
binary |
1 |
left |
Precedence specifies in which order operations are performed. For example, since multiplication has a higher precedence than addition (13 versus 12), if no parenthesis are supplied, the expression a*b+c is evaluated as (a*b)+c.
Associativity
Associativty specifies in what order operations are performed when we have several operators with the same precedence level. Operators are classified as either left or right associative. If an operator group is left associative, the operators at the same precedence level are evaluated left to right. If an operator group is right associative, the operators at the same precedence level are evaluated right to left.
For example, if we have the following:
int a = 1, b = 2, c = 3; cout << (a-b+c) << endl;
prints 2 [evaluates as (1-2)+3 rather than 1-(2+3)] since addition and subtraction are the same precedence level, and the operators are left associative (evaluated left to right).
If we have the following:
int a = 1, b = 2, c = 3; a -= b += c; cout << a << " " << b << " " << c << endl;
prints -4 5 3 [evaluates as a -= (b += c) rather than (a -= b) += c which would print 2 3 3] since the assignment operators are the same precedence level, and the operators are right associative (evaluated right to left).
|
Original Expression |
Equivalent Expression |
Rationale |
|---|---|---|
| a*b+c | (a*b)+c | * has higher precedence than + |
| a+=b|=c | a+=(b|=c) | += and |= are right associative |
| a-b+c | a-(b+c) | - and plus are left associative. |
| *p->q | *(p->q) | -> has higher precedence than * |
| *x++ | *(x++) | ++ has higher precedence than * |
Consider:
#include <stdio.h>
#define SIZE 5
int main() {
int x[SIZE], *p, i, j;
for(i=0; i < SIZE; i++) x[i] = 0;
p = &x[2];
printf("the address p is pointing at now is %p\n",p);
j = ++*p++; /* which is evaluated as (++(*(p++))) */
printf("the value of j is %d\n",j);
printf("the address p is pointing at now is %p\n",p);
for(i=0; i < SIZE; i++)
printf("x[%d] = %d and is at location %p\n",i, x[i], &x[i]);
}
Program Output
the address p is pointing at now is 3E77:2260 the value of j is 1 the address p is pointing at now is 3E77:2262 x[0] = 0 and is at location 3E77:225C x[1] = 0 and is at location 3E77:225E x[2] = 1 and is at location 3E77:2260 x[3] = 0 and is at location 3E77:2262 x[4] = 0 and is at location 3E77:2264
Interpretation
The statement j = ++*p++ contains the following operators:
| ++ | postfix increment operator, precedence 17, left associative. |
| ++ | prefix increment operator, precedence 15, right associative. |
| * | unary indirection operator, precedence 15, right associative. |
| = | binary assignment operator, precedence 2, right associative. |
Applying the operators in precedence order, since the ++ postfix increment operator has the highest precedence, it is applied first. This gives us:
j = ++*(p++)
Next, the ++ prefix operator and the * unary indirection operator have the same precedence level (precedence 15). Since they are right associative, they are applied right to left as:
j = ++(*(p++)) j = (++(*(p++)))
Lastly, the assignment operator (precedence 2) is applied.
The execution of this now follows the rules of the pre and post increment operators. The postincrement part of this [ (p++) ] is executed after the assignment expression is executed. The preincrement part of this [ ++(*p) ] is executed before the assignment expression is evaluated. This whole expression is equivalent to the following statements:
*p = *p + 1; /* increment the value pointed at by p */ j = *p; /* assign j the value pointed at by p */ p = p + 1; /* increment the pointer p */
The Bottom Line
Don't do weird stuff like this unless you would like to turn every program development exercise into a research project. Use parenthesis to clarify your meaning, always.