Reputation: 3774
When I run this toy program,
#include<stdio.h>
int main(void)
{
int arr[] = {11, 22, 33};
int *ptr = arr;
printf("ptr at: %p\n", (void *)ptr);
printf("Result of expression: %d\n", *ptr++); // line 8
printf("ptr at: %p\n", (void *)ptr);
}
the output I get is:
ptr at: 0x7fffffffdbf0
Result of expression: 11
ptr at: 0x7fffffffdbf4
My understanding on what happens on line 8
is that, per precedence rules (the post increment ++
has higher precedence than the dereference *
) the expression *ptr++
is equivalent to *(ptr++)
. Here is a nice explanation which I went through. But, in that explanation there is no mention of sequence points.
Throwing sequence points in the mix, I assume that 11
is printed because ptr
is incremented only after the sequence point (which happens to be after all the arguments to printf
are evaluated) is reached. And, the post increment operator actually does it's job (of increasing and writing) after the sequence point. Is my understanding correct?
Upvotes: 1
Views: 158
Reputation: 8589
No.The value of 11 is used because the value of the expression ptr++
is the value of ptr
before it is incremented. Full stop. No sequence point here!
A sequence point does happen before the function is entered in the function call and the relevance of sequence points is that the increment of ptr must have taken place before the function is entered.
Here's code that shows that happening:
#include <stdio.h>
int arr[] = {11, 22, 33};
int *ptr = arr;
int indirect(const char *fmt,int val){
printf("peek: %p (%d)\n",ptr,*ptr);
return printf(fmt,val);
}
int main(void)
{
printf("ptr at: %p\n", (void *)ptr);
indirect("Result of expression: %d\n", *ptr++); // line 8
printf("ptr at: %p\n", (void *)ptr);
}
Typical output:
ptr at: 0x2ac98105b030
peek: 0x2ac98105b034 (22)
Result of expression: 11
ptr at: 0x2ac98105b034
The rules about sequence points are telling you that the second must show ptr
incremented and must have (22)
on the end.
It would violate the function call sequence point rule if we saw peek: 0x2ac98105b030 (11)
but ptr at: 0x2ac98105b034
in the last line.
That would mean the side-effect (i.e. increment of ptr
) had taken place after the entry to indirect()
.
Precedence defines the order of evaluation but sequence points specify points before which side-effects must have taken place.
A good way to reason about them is to separate the concerns of evaluation and side-effect. Go through evaluating expressions and write down all the side-effects and then look at sequence point rules that tell you when they must have taken place before.
If you do that here (key steps in line 8):
int
).ptr
taken in step 1.printf()
. Step 4 is a sequence point so we must make sure step 2 happens before 4. But it could happen before 3.
it's easy to get confused in C because the pre- and post-increment operators seen to have sequencing in their definition.
Think of p++ as "take the value of p and side-effect increment p". Think of ++p as "take the value of p+1 and side-effect increment p" not as "increment p and take its value".
That second phrasing for ++p
implies a sequencing that the standard doesn't guarantee and while may take place is definitely not guaranteed.
Upvotes: 1
Reputation: 213711
My understanding on what happens on line 8 is that, per precedence rules (the post increment ++ has higher precedence than the dereference *) the expression *ptr++ is equivalent to *(ptr++)
This is correct.
Throwing sequence points in the mix...
This doesn't really have anything to do with sequence points as such, but rather with the behavior of postfix ++, which is specified as (6.5.2.4):
The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented.
/--/
The value computation of the result is sequenced before the side effect of updating the stored value of the operand.
In plain English this means that an expression ptr++
will first "return" the value of ptr
, which will be used as the result of the expression, and then afterwards increment ptr
by 1.
As for the whole expression printf("Result of expression: %d\n", *ptr++);
, there is a sequence point after the evaluation of all function parameters, but before the function is called. Plus a few more after that.
The program flow is like this:
"Result of expression: %d\n"
and *ptr++
. This can be done in any order.For the sub-expression *ptr++
, evaluate its sub-expressions. Operator precedence dictates that ptr++
makes one sub-expression. So evaluate this expression to the value of ptr
and store the result.
a) Evaluate the *
operator with the stored result as operand. Store the evaluated result, to be passed to the function.
b) Increase ptr
by 1.
3a) and 3b) can be sequenced in any order in relation to each other.
;
.As you can see, the sequence points are mostly irrelevant to the evaluation of the *ptr++
expression. The only time the sequence point comes into play, is that C dictates that the ++ must have happened before it. But the ++ can happen anywhere between 2) and 5).
Upvotes: 5
Reputation: 86651
I assume that 11 is printed because ptr is incremented only after the sequence point (which happens to be after all the arguments to printf are evaluated)
Nope. It's nothing to do with sequence points. A post increment expression increments its argument but the value of the expression is the value of the argument before the increment.
For an int*
the post increment looks a lot like this function:
int* postInc(int** p)
{
int* tmp = *p;
*p = *p + 1;
return tmp;
}
And *p++
would look like this:
*postInc(&p);
Upvotes: 6