3

§5.1.2.4.16

EXAMPLE 7 The grouping of an expression does not completely determine its evaluation. In the following fragment:

#include <stdio.h>
int sum;
char *p;
/*
...
*/
sum = sum * 10 - '0' + (*p++ = getchar());

the expression statement is grouped as if it were written as

sum = (((sum * 10) - '0') + ((*(p++)) = (getchar())));

but the actual increment of p can occur at any time between the previous sequence point and the next sequence point (the ; ), and the call to getchar can occur at any point prior to the need of its returned value.

So basically I understand this as unspecified behavior - either *p = getchar(); p++; OR p++; *p = getchar(). Note that the ; implies a sequence point, but there are no other sequence points in the whole expression.

So this syntax is useless. And, pretty much, ++ and -- for pointer assignment is useless. Right?

Community
  • 1
  • 1
Vorac
  • 8,726
  • 11
  • 58
  • 101
  • 1
    It doesn't matter when the `p++` post-increment happens, because p is only evaluated once in the expression. – Paul R Apr 29 '13 at 10:01
  • in `(*p++ = getchar())` , the `p++` is only a side effect, `p` is never referenced at a second place in the same statement, so `p++` *cannot* cause sequence point errors. (except if it would point to `sum`, or somewhere inside the buffer of the stdin FILE) – wildplasser Apr 29 '13 at 10:01
  • change `p* = getchar()` to `*p = getchar()` – Rüppell's Vulture Apr 29 '13 at 14:37

4 Answers4

6

The lexical grouping is irrelevant. What matters is the value of p++.

The statement is identical to the following two statements:

sum = sum * 10 - '0' + (*p = getchar());
++p;
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I still don't understand why the following does not happen: 1) evaluate p++ 2) evaluate getchar() 3) assign the returned value to the now incremented p pointer. When does the postfix increment occur? – Vorac Apr 29 '13 at 10:14
  • 1
    @Vorac You were just told. It doesn't matter *when* p++ occurs ... that doesn't affect the *value* of `p` in `*p` ... that value is, by definition, the value of `p` before the increment occurs. – Jim Balter Apr 29 '13 at 10:18
  • 1
    @Vorac: evaluating `p++` gives the exact same value as evaluating `p` (only `p++` is an rvalue, while `p` is an lvalue). – Kerrek SB Apr 29 '13 at 10:28
6

either *p = getchar(); p++; OR p++; p* = getchar() [sic]

Well actuall no. It's either:

*p = getchar(); p++

or

old_p = p++; *old_p = getchar()

In your interpretation, you could either write at *p or *(p + 1) which is not true. In both interpretations, you write to where p originally pointed to, regardless of when the compiler decides to put the instruction that changes p. If it decides to put it before the write to *p, then it would have to make sure it keeps the old value to later write to (*old_p).

The suffix -- and ++ operators are actually quite nice shortcuts. Take this example:

size_t strlen(const char *str)
{
    size_t len = 0;
    while (str[len++]);
    return len - 1;
}

This is a very concise implementation of strlen using suffix ++.


From C11, 6.5.2.4.2 (emphasis mine):

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). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. 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. Postfix ++ on an object with atomic type is a read-modify-write operation with memory_order_seq_cst memory order semantics.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • Sounds like there is some rule that postfix operators take effect after the **expression** finishes. This is puzzling. The standard says "all side effects have to be completed until the next sequence point". But here it seems to be a requirement that ++ is applied **after** some event. What event? – Vorac Apr 29 '13 at 10:21
  • You should `return len-1;` Imagine what would happen in the case of the empty string `""` as the `str` argument. – wildplasser Apr 29 '13 at 10:22
  • 1
    @Vorac: there is no such rule. Please believe Shahbaz when he tells you that the value of `p++` is the old value of `p`. It does not matter when `p` is modified, because the old value is the same either way, and so `*p++` refers to the same `char` regardless of when `p` is incremented. – Steve Jessop Apr 29 '13 at 10:23
  • 2
    "sounds like there is some rule that postfix operators take effect after the expression finishes" -- No it doesn't. Why not try reading and comprehending the answers you have been given? or for that matter reading the C Standard, which clearly and plainly defines the value of `p` in `*p++` to be the value before being incremented, *regardless of when it is incremented*. And don't laugh at Steve's valid comment. – Jim Balter Apr 29 '13 at 10:24
  • @Steve Jessop, "Please believe Shahbaz" hahahaha :) A good one! – Vorac Apr 29 '13 at 10:24
  • The key word is `side effect` here. Please see my comment to the OP. – wildplasser Apr 29 '13 at 10:25
3
sum = (((sum * 10) - '0') + ((*(p++)) = (getchar())));

is equivalent to

*p = getchar();
sum = ( ((sum * 10) - '0') + *p );
p++;

it was reduced to 1 line. and it's not useless because writing code in such way will allow to reduce the size and the complexity of your code

sum = (((sum * 10) - '0') + ((*(++p)) = (getchar())));

is equivalent to

p++;
*p = getchar();
sum = ( ((sum * 10) - '0') + *p );
pagid
  • 13,559
  • 11
  • 78
  • 104
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
0

Using -- and ++ for pointer assignments isn´t actually useless. Consider a loop where you want to read 10 characters and add the escape character at the end:

int i, sum;
char * p;
p = (char*) malloc(11 * sizeof(char));

for (i = 0; i < 10; i++){
   sum = sum * 10 - '0' + (*p++ = getchar());
}
*p = '\0';
Evans
  • 1,589
  • 1
  • 14
  • 25
  • What's a bucle? Anyway, this doesn't address the OP's question. – Jim Balter Apr 29 '13 at 10:22
  • @JimBalter bucle = loop (language issue, sorry). And at the end of his post, he said: "So this syntax is useless. And, pretty much, ++ and -- for pointer assignment is useless. Right?" – Evans Apr 29 '13 at 10:25
  • In order not to lose p for future use you could add `for(; sum; sum/=10) { p--;}` after the `*p = '\0';` ;-) Which would fail for the `(sum%10 == 0)` case ... – wildplasser Apr 29 '13 at 10:32
  • It doesn't address the OP's reasons for thinking that it's useless ... that's what this is all about. – Jim Balter Apr 29 '13 at 10:33