Keith Thompson wrote:
> Shao Miller <> writes:
>> pete wrote:
>>> Shao Miller wrote:
>>>> pete wrote:
>>>>> Martin O'Brien wrote:
>>>>>> int a = 1;
>>>>>> printf("%d", ++a, a + 5);
>>>> Will someone please explain
>>>> why 'a + 5' has an undefined value?
>>> What is the value of (a + 5) ?
>>>
>> 6 for a conforming implementation. 6 or 7 for a non-confrming one. In
>> a conforming implementation, the value of 'a' (which is non-'volatile')
>> is not changed until the sequence point immediately before the function
>> call to 'printf'.
>
> Where does the standard say that the side effect of incrementing a must
> not occur until the sequence point? (Hint: It doesn't.)
Thanks for pointing this out, Keith!

This is a critical flaw to my
argument.
"...At certain specified points in the execution sequence called
sequence points, all side effects of previous evaluations shall be
complete and no side effects of subsequent evaluations shall have taken
place."
This does not imply that side effects are prohibited between sequence
points and only completed as a sequence point is passed.
>
>> No evaluation of any of the multiple expressions in the argument list
>> leads to undefined behaviour, so the integrity of the abstract machine's
>> operation in also intact. Would you agree that the expressions in the
>> argument list are not a single expression (although it might look like
>> an expression with multiple comma operators, for example)?
>
> The expression in question is the entire function call.
> By themselves, the subexpressions ++a and a + 5 are well defined.
> But because they appear together as part of a larger expression
> with no intervening sequence points, the behavior is undefined.
>
This is another critical flaw to my argument. Treating the entirety of
'printf("%d", ++a, a + 5)' as an expression qualifies it as a single
expression for the treatment of:
"Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression..."
This particular argument you offer requires that:
For any expression, if a side effect during evaluation of that
expression would modify the value of an object, then the previous value
of that object shall be read only as part of a computation for the new
value of the object.
In fact, that's nearly what the text states, and why we could expect:
int i = 1, b;
b = ++i + i;
to be undefined. But please also recognize the possible implication of
"only". Does this prevent a larger expression with the same sequence
point boundaries from doing anything else but a modification of the
object? This larger expression can have other side effects.
So an interpretation could be that the value cannot be used outside of
the sub-expression which directly provides the value to be stored. Then
the latter line of:
int i = 1, j;
i = j = i + i;
would be grouped as:
i = (j = (i + i));
and we are fine in that 'i' is only read within the sub-expression
immediately responsible for the new value. We should not:
int i, j;
/* Uh oh */
j = (i + (i = (1)));
because there's a read of 'i' outside of the the sub-expression for the
new value. Would you agree?
int i = 1, j = 1, k = 1;
/* Fine */
k = ((j = ((i = (i + j + k)) + j + k)) + k);
int i = 0, j;
int *ip = &i;
/* Uh oh, 'i' reads outside of the sub-expression */
*(ip + i) = (i + 5);
*(ip + (j = i)) = (i + 5);
Would you agree?
> Once again, 6.5p2:
>
> Between the previous and next sequence point an object shall
> have its stored value modified at most once by the evaluation
> of an expression. Furthermore, the prior value shall be read
> only to determine the value to be stored.
>
> The printf violates the second sentence; the second subexpression a +
> 5 reads the value of a, but not to determine the value to be stored.
>
> That second sentence can be confusing (it confused me for a long
> time). The point is that if an object is read just to determine
> the value to store in that same object, there's no problem, since
> the read logically has to occur before the write. But if the object
> is read in a part of the expression that doesn't contribute to the
> computation of the value to be stored, then the read and the write
> could occur in either order, at the whim of the compiler.
Agreed. lacos and Willem explained how simultaneous reads and writes
could be a problem.
>
> The authors of the standard *could* have placed some limitations
> on how such expressions are evaluated, saying, for example, that
> either ++a must be evaluted (including its side effect) before a +
> 5, or vice versa. But that would constrain the optimizations that
> compilers are able to perform and make the standard more complex.
That would be a Bad Thing.
> And it's generally easy enough to avoid writing such code in the
> first place.
>
Agreed. I appreciate your explanatory efforts here, Keith.