Handout 22

Expressions and Precedence



Each expression operator in C has a precedence level and a rule of associativity. Where operators do not explicitly indicate the grouping of operands with operators, the operands are grouped with the operator having higher precedence. If two operators have the same precedence, the operand is grouped with the left or right operator according whether the operators are left associative or right associative. All operators of the same precedence level have the same associativity.

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

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;
printf("%d\n",a-b+c);

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;
printf("%d %d %d\n",a ,b, c);

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).


Examples

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 *


The Last Weird Example

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.