(p++)->x Why are the parentheses unnecessary? (K&R) - c

From page 123 of The C Programming Language by K&R:
(p++)->x increments p after accessing x. (This last set of parentheses is unnecessary. Why?)
Why is it unnecessary considering that -> binds stronger than ++?
EDIT: Contrast the given expression with ++p->x, the latter is evaluated as ++(p->x) which would increment x, not p. So in this case parentheses are necessary and we must write (++p)->x if we want to increment p.

The only other possible interpretation is:
p++(->x)
and that doesn't mean anything. It's not even valid. The only possible way to interpret this in a valid way is (p++)->x.

Exactly because -> binds stronger than ++. (it doesn't, thanks #KerrekSB.)
increments p after accessing x.
So first you access x of p, then you increment p. That perfectly matches the order of evaluation of the -> and the + operators.
Edit: aww, these edit's...
So what happens when you write ++p->x is that it could be interpreted either as ++(p->x) or as (++p)->x (which one is actually chosen is just a matter of language design, K&R thought it would be a good idea to make it evaluate as in the first case). The thing is that this ambiguity doesn't exist in the case of p++->x, since it can only be interpreted as (p++)->x. The other alternatives, p(++->x), p(++->)x and p++(->x) are really just syntactically malformed "expressions".

The maximal munch strategy says that p++->x is divided into the following preprocessing tokens:
p then ++ then -> then x
In p++->x expression there are two operators, the postfix ++ operator and the postifx -> operator. Both operators being postfix operators, they have the same precedence and there is no ambiguity in parsing the expression. p++->x is equivalent to (p++)->x.
For ++p->x expression, the situation is different.
In ++p->x, the ++ is not a postfix operator, it is the ++ unary operator. C gives postfix operators higher precedence over all unary operators and this is why ++p->x is actually equivalent to ++(p->x).
EDIT: I changed the first part of the answer as a result of Steve's comment.

Both post-increment and member access operator are postfix expressions and bind the same. Considering that they apply to the primary or postfix expression to the left, there can't be ambiguity.
In
p++->x
The postfix-++ operator can apply only to the expression to the left of it (i.e. to p).
Similarly ->x can only be an access to the expression to its left, which is p++. Writing that expression as (p++) is not needed, but also does no harm.
The "after" in your description of the effects, does not express temporal order of increment and member access. It only expresses that the result of p++ is the value p had before the increment and that that value is the value used for the member access.

The expresion p++ results in a pointer with the value of p. Later on, the ++ part is performed, but for the purposes of interpreting the expression, it may just as well not be there. ->x makes the compiler add the offset for the member x to the original address in p and access that value.
If you change the statement to :
p->x; p++;
it would do exactly the same thing.
The order of precedence is actually exactly the same, as can be seen here - but it doesn't really matter.

Related

*p++->str : Understanding evaluation of ->

My question is about the following line of code, taken from "The C Programming Language" 2nd Edition:
*p++->str;
The book says that this line of code increments p after accessing whatever str points to.
My understanding is as follows:
Precedence and associativity say that the order in which the operators will be evaluated is
->
++
*
The postfix increment operator ++ yields a value (i.e. value of its operand), and has the side effect of incrementing this operand before the next sequence point (i.e. the following ;)
Precedence and associativity describe the order in which operators are evaluated and not the order in which the operands of the operators are evaluated.
My Question:
My question is around the evaluation of the highest precedence operator (->) in this expression. I believe that to evaluate this operator means to evaluate both of the operands, and then apply the operator.
From the perspective of the -> operator, is the left operand p or p++? I understand that both return the same value.
However, if the first option is correct, I would ask "how is it possible for the evaluation of the -> operator to ignore the presence of the ++".
If the second option is correct, I would ask "doesn't the evaluation of -> in this case then require the evaluation of a lower precedence operator ++ here (and the evaluation of ++ completes before that of ->)"?
To understand the expression *p++->str you need to understand how *p++ works, or in general how postfix increment works on pointers.
In case of *p++, the value at the location p points to is dereferenced before the increment of the pointer p.
n1570 - ยง6.5.2.4/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.
In case of *p++->str, ++ and -> have equal precedence and higher than * operator. This expression will be parenthesised as *((p++)->str) as per the operator precedence and associativity rule.
One important note here is precedence and associativity has nothing to do with the order of evaluation. So, though ++ has higher precedence it is not guaranteed that p++ will be evaluated first. Which means the expression p++ (in the expression *p++->str) will be evaluated as per the rule quoted above from the standard. (p++)->str will access the str member p points to and then it's value is dereferenced and then the value of p is incremented any time between the last and next sequence point.
Postfix ++ and -> have the same precedence. a++->b parses as (a++)->b, i.e. ++ is done first.
*p++->str; executes as follows:
The expression parses as *((p++)->str). -> is a meta-postfix operator, i.e. ->foo is a postfix operator for all identifiers foo. Postfix operators have the highest precedence, followed by prefix operators (such as *). Associativity doesn't really apply: There is only one operand and only one way to "associate" it with a given operator.
p++ is evaluated. This yields the (old) value of p and schedules an update, setting p to p+1, which will happen at some point before the next sequence point. Call the result of this expression tmp0.
tmp0->str is evaluated. This is equivalent to (*tmp0).str: It dereferences tmp0, which must be a pointer to a struct or union, and gets the str member. Call the result of this expression tmp1.
*tmp1 is evaluated. This dereferences tmp1, which must be a pointer (to a complete type). Call the result of this expression tmp2.
tmp2 is ignored (the expression is in void context). We reach ; and p must have been incremented before this point.

Undefined behaviour seems to be contradicting with operator precedence rule in C [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 4 years ago.
Consider the following line of code.
int i = 2;
i = i++
The second line of code has been identified as undefined. I know this question has been asked before several times and example being this.
But nowhere could I see the issue of operator precedence being addressed in this issue. It has been clearly mentioned that postfix operator precedes assignment operator.
i = (i++)
So clearly i++ will be evaluated first and this value of i is the assigned to i again.
This looks like this particular undefined behavior is contradicting the precedence rule.
Similar to this is the code:
int i = 2;
i++ * i++;
Here according to operator precedence the code can be written as
int i =2;
(i++) * (i++)
Now we do not know whether the (i++) in LHS or RHS of '*' operator is going to be evaluated first. But either way it is going produce the same result. So how is it undefined?
If we write say:
int p;
p = f1() + f2()
where f1() and f2() are defined functions then obviously it's clear we can't decide whether f1() or f2() is going to be evaluated first as precedence rules does not specify this. But a confusion like this does not seem to arise in the current problem.
Please explain.
I do not understand why this question got a negative vote. I needed a clarity between operator precedence and UB and I have seen no other question addressing it.
What you're looking for is in section 6.5 on Expressions, paragraph 3 of the C standard:
The grouping of operators and operands is indicated by the syntax.
Except as specified later, side effects and value computations of
subexpressions are unsequenced.
This means that the side effect of incrementing (or decrementing) via the ++ or -- operators doesn't necessarily happen immediately when the operator is encountered. The only guarantee is that it happens before the next sequence point.
In the case of i = i++;, there is no sequence point in the evaluation of the operands of = nor in the evaluation of postfix ++. So an implementation is free to perform assigning the current value of i to itself and the side effect of incrementing of i in any order. So i could potentially be either 2 or 3 in your example.
This goes back to paragraph 2:
If a side effect on a scalar object is unsequenced relative
to either a different side effect on the same scalar object
or a value computation using the value of the same scalar
object, the behavior is undefined.
Since i = i++ attempts to update i more than once without a sequence point, it invokes undefined behavior. The result could be 2 or 3, or something else might happen as a result of optimizations for example.
The reason that this is not undefined:
int p;
p = f1() + f2()
Is because a variable is not being updated more than once in a sequence point. It could however be unspecified behavior if both f1 and f2 update the same global variables, since the evaluation order is unspecified.
The problem with using
i = i++
is that the order in which the address of i is accessed to read and write is not specified. As a consequence, at the end of that line, the value of i could be 3 or 2.
When will it be 3?
Evaluate the RHS - 2
Assign it to the LHS. i is now 2.
Increment i. i is now 3.
When will it be 2?
Evaluate the RHS - 2
Increment i. i is now 3.
Assign the result of evaluating the RHS to the LHS. i is now 2.
Of course, if there is a race condition, we don't know what's going to happen.
But nowhere could I see the issue of operator precedence being addressed in this issue.
Operator precedence only affects how expressions are parsed (which operands are grouped with which operators) - it has no effect on how expressions are evaluated. Operator precedence says that a * b + c should be parsed as (a * b) + c, but it doesn't say that either a or b must be evaluated before c.
Now we do not know whether the (i++) in LHS or RHS of '*' operator is going to be evaluated first. But either way it is going produce the same result. So how is it undefined?
Because the side effect of the ++ operator does not have to be applied immediately after evaluation. Side effects may be deferred until the next sequence point, or they may applied before other operations, or sprinkled throughout. So if i is 2, then i++ * i++ may be evaluated as 2 * 2, or 2 * 3, or 3 * 2, or 2 * 4, or 4 * 4, or something else entirely.
OPERATOR PRECEDENCE DOES NOT RESOLVE UNDEFINED EXPRESSION ISSUES.
Sorry for shouting, but people ask about this all the time. I'm afraid I have to say your research on this question must not have been very thorough, if you didn't see this aspect being discussed.
See for example this essay.
The expression i = i++ tries to assign to object i twice. It's therefore undefined. Period. Precedence doesn't save you.

C operator order

Why is the postfix increment operator (++) executed after the assignment (=) operator in the following example? According to the precedence/priority lists for operators ++ has higher priority than = and should therefore be executed first.
int a,b;
b = 2;
a = b++;
printf("%d\n",a);
will output a = 2.
PS: I know the difference between ++b and b++ in principle, but just looking at the operator priorities these precende list tells us something different, namely that ++ should be executed before =
++ is evaluated first. It is post-increment, meaning it evaluates to the value stored and then increments. Any operator on the right side of an assignment expression (except for the comma operator) is evaluated before the assignment itself.
It is. It's just that, conceptually at least, ++ happens after the entire expression a = b++ (which is an expression with value a) is evaluated.
Operator precedence and order of evaluation of operands are rather advanced topics in C, because there exists many operators that have their own special cases specified.
Postfix ++ is one such special case, specified by the standard in the following manner (6.5.2.4):
The value computation of the result is sequenced before the side
effect of updating the stored value of the operand.
It means that the compiler will translate the line a = b++; into something like this:
Read the value of b into a CPU register. ("value computation of the result")
Increase b. ("updating the stored value")
Store the CPU register value in a.
This is what makes postfix ++ different from prefix ++.
The increment operators do two things: add +1 to a number and return a value. The difference between post-increment and pre-increment is the order of these two steps. So the increment actually is executed first and the assignment later in any case.

Issue with precedence and ++ and * unary operators in C

My question is not long, but it's puzzling for me. I'm one of those people who (and I think rightfully so) want to know every single rule of the languages they learn. I want to know why the language does what it does.
So, why does ++*i increment the value of *i, rather than the i pointer? The preincrement operator has a higher precedence than the indirection operator. It seems like a common sense thing, but again, I must know exactly why. Please provide references if you can.
It cannot be parsed as *(++i), can it?
By the way, * and prefix ++ have the same precedence, and right-to-left associativity.
Prefix ++ has same precedence as unary * while postfix ++ hsa higher precedence than unary * operator.
In case of ++ *i compiler interpret it as
++ (*i);
That means, dereference i, use it, increment the dereferenced value without changing the value of pointer.

Confusing answers : One says *myptr++ increments pointer first,other says *p++ dereferences old pointer value

I would appreciate if you clarify this for me.Here are two recent questions with their accepted answers:
1) What is the difference between *myptr++ and *(myptr++) in C
2) Yet another sequence point query: how does *p++ = getchar() work?
The accepted answer for the first question,concise and easily to understand states that since ++ has higher precedence than *, the increment to the pointer myptr is done first and then it is dereferenced.I even checked that out on the compiler and verified it.
But the accepted answer to the second question posted minutes before has left me confused.
It says in clear terms that in *p++ strictly the old address of p is dereferenced. I have little reason to question the correctness of a top-rated answer of the second question, but frankly I feel it contradicts the first question's answer by user H2CO3.So can anyone explain in plain and simple English what the second question's answer mean and how come *p++ dereferences the old value of p in the second question.Isn't p supposed to be incremented first as ++ has higher precedence?How on earth can the older address be dereferenced in *p++Thanks.
The postfix increment operator does have higher precedence than the dereference operator, but postfix increment on a variable returns the value of that variable prior to incrementing.
*myptr++
Thus the increment operation has higher precedence, but the dereferencing is done on the value returned by the increment, which is the previous value of myptr.
The answer in the first question you've linked to is not wrong, he's answering a different question.
There is no difference between *myptr++ and *(myptr++) because in both cases the increment is done first, and then the previous value of myptr is dereferenced.
The accepted answer for the first question,concise and easily to understand states that since ++ has higher precedence than *,
Right. That is correct.
the increment to the pointer myptr is done first and then it is dereferenced.
It doesn't say that. Precedence determines the grouping of the subexpressions, but not the order of evaluation.
That the precedence of ++ is higher than the precedence of the indirection * says that
*myptr++
is exactly the same (not on the cource code level, of course) as
*(myptr++)
and that means that the indirection is applied to the result of the
myptr++
subexpression, the old value of myptr, whereas (*myptr)++ would apply the increment operator to what myptr points to.
The result of a postfix increment is the old value of the operand, so
*myptr++ = something;
has the same effect as
*myptr = something;
myptr++;
When the side-effect of storing the incremented value of myptr happens is unspecified. It may happen before the indirection is evaluated, or after that, that is up to the compiler.
Section 6.5.2.4 of the C specification discusses the postfix increment and decrement operators. And the second paragraph there pretty much answers your question:
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.
So given *myptr++, yes it's true the the ++ part has higher precedence; but precedence does not exclusively determine your result. The language defines that with the specs. In this case the value of myptr is returned, then the "side effect" of myptr being incremented is executed.

Categories

Resources