C Operator Precedence postfix increment and dereference

Viewed 229

Here is another naïve question from a C newbie: on this page, https://en.cppreference.com/w/c/language/operator_precedence, the precedence of the postfix increment is listed to be higher than that of pointer dereference. So I was expecting in the following code that the pointer is incremented first (pointing at 10) and then dereferenced.

#include <stdio.h>

int main()
{
  int a[] = {3, 10, 200};
  int *p = a;
  printf("%d", *p++);
  return 0;
}

However this code outputs still the first array item (3). What am I missing by the concept?

4 Answers

Precedence is placing of parenthesis.

The expression *p++ can be parenthesized as

(*p)++ // incorrect precedence
*(p++) // correct precedence

Note that the value of p++ is the value of p before any change, so the net effect of the correct precedence is the same as *p without ant reflection over the side-effect ++. The change to p itself does not alter the result of *(p++).

As you have correctly assumed, the expression *p++ is evaluated as *(p++); that is, the ++ operator has higher precedence than the * operator.

However, the value of the expression, p++, is just the value of p (i.e. its value before the increment). A side-effect of the operation is that the value of p is incremented after its value has been acquired.

From this Draft C11 Standard:

6.5.2.4 Postfix increment and decrement operators


2     The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). … The value computation of the result is sequenced before the side effect of updating the stored value of the operand. With respect to an indeterminately-sequenced function call, the operation of postfix ++ is a single evaluation. …

Operator precedence specifies how an expression is parsed. Since postfix ++ has higher precedence than *, the expression is equivalent to *(p++). Rather than (*p)++ which would have given it a completely different meaning.

But just because this forces p++ to be evaluated first, it doesn't affect the characteristic of the ++ operator. The C language specifies this operator to behave as (from C17 6.5.2.4/2):

"The value computation of the result is sequenced before the side effect of updating the stored value of the operand."

This means that p++ always gives the value of p before ++ is applied. In this case p is a pointer, so the value will be the address it pointed at prior this expression. So the code is completely equivalent to this:

int* tmp = p;
p++;
printf("%d", *tmp);

Precedence controls which operators are grouped with which operands. Postfix ++ having higher precedence than unary * simply means that *p++ is parsed as *(p++) instead of (*p)++.

*(p++) means you are dereferencing the result of p++. The result of p++ is the current value of p. As a side effect p is incremented. It is logically equivalent to

tmp = p;
printf( "%d\n", *tmp );
p = p + 1;

where the printf call and the update to p can happen in any order, even simultaneously (interleaved or in parallel).

Related