In fact... oh dear...
I should make an effort to get some sleep before posting these
questions :-)
If it is too late to cancel the post, then I might as well answer my
own stupidity:
> Given the following (albeit overly simplified) example:
>
> int a;
>
> int
> main()
> {
> int b, c;
> int d = (a = 1, ++b) + (a = 2, ++c);
> return 0;
>
> }
>
> Can we be certain about 'a' always being '1' when '++b' is evaluated;
> and 'a' always being '2' by the time '++c' is evaluated?
No -- Interleaved evaluations are possible in this case.
>
> Would one also be correct in thinking that rewriting the above as
>
> int a;
> int boo()
> {
> int b;
> a = 1;
> return ++b;}
>
> int goo()
> {
> int c;
> a = 2;
> return ++c;}
>
> int
> main()
> {
> int d = boo() + goo();
> return 0;
>
> }
>
> then the same answer to the above (i.e. "Can we be certain about 'a'
> always being '1' when '++b' is evaluated; and 'a' always being '2' by
> the time '++c' is evaluated?") would hold?
No. Functions do not interleave.
PS -- what was I thinking ?!
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
a=1
a=2
++c
++b
Remember that sequence points are about side effects. The side effect of
evaluating a=1 is to write to the storage for a, the value of a=1 is 1.
There is no guarantee that the writing of 1 to the storage for a has
completed before evaluating a=2 starts.
> Hi, the following is rather trivial and I should know this... but my
> brain is fried atm... so I thought I'd verify...
>
> Given the following (albeit overly simplified) example:
>
> int a;
>
> int
> main()
> {
> int b, c;
> int d = (a = 1, ++b) + (a = 2, ++c);
> return 0;
> }
>
> Can we be certain about 'a' always being '1' when '++b' is evaluated;
> and 'a' always being '2' by the time '++c' is evaluated?
>
No, because behavior is undefined. While there is a sequence point between
evaluations of "a = 1" and "++b" and between "a = 2" and "++c", there is no
sequence point between evaluations of "a = 1" and "a = 2".
> In other words, whilst it is absolutely clear that the order of
> operands for '+' is undefined, is there a guarantee of "atomicity" for
> the operands in the above example -- i.e. when one of the operands
> *begins* being evaluated (e.g. (a = 2, ++c)), then it will be
> *completely* evaluated before, or after, another operand is started to
> be evaluated (e.g. (a = 1, ++b)) ?
>
There is no such "atomicity".
> Would one also be correct in thinking that rewriting the above as
>
> int a;
> int boo()
> {
> int b;
> a = 1;
> return ++b;
> }
> int goo()
> {
> int c;
> a = 2;
> return ++c;
> }
> int
> main()
> {
> int d = boo() + goo();
> return 0;
> }
>
> then the same answer to the above (i.e. "Can we be certain about 'a'
> always being '1' when '++b' is evaluated; and 'a' always being '2' by
> the time '++c' is evaluated?") would hold?
>
Yes, behavior is UB again, but not because of the same reason. In this
snippet, you read a non-initialized variable. There is however no change to
the value of a scalar between the previous and the next sequence point
anymore, because before and after a function runs, there is a entry and exit
sequence point, and while a function runs, no evaluations of the calling
function is processed. If you had initialized "b" and "c" behavior would be
perfectly fine.
We can't.
> In other words, whilst it is absolutely clear that the order of
> operands for '+' is undefined, is there a guarantee of "atomicity" for
> the operands in the above example -- i.e. when one of the operands
> *begins* being evaluated (e.g. (a = 2, ++c)), then it will be
> *completely* evaluated before, or after, another operand is started to
> be evaluated (e.g. (a = 1, ++b)) ?
There is no such guarantee. Sub-expressions with no intervening sequence
points can be evaluated in parallel. In your expression:
int d = (a = 1, ++b) + (a = 2, ++c);
There are two sequence points where the comma operator is. It requires
the compiler to evaluate the assignment of 1 to a before ++b and the
assignment of 2 to a before ++c. There is no requirement, however, that
a = 1 is evaluated before a = 2 or after. The compiler can evaluate this
as a sequence a=1,a=2,++b,++c, or optimize it to a=2,++b,++c.
> Would one also be correct in thinking that rewriting the above as
>
> int a;
> int boo()
> {
> int b;
> a = 1;
> return ++b;
> }
> int goo()
> {
> int c;
> a = 2;
> return ++c;
> }
> int
> main()
> {
> int d = boo() + goo();
> return 0;
> }
>
> then the same answer to the above (i.e. "Can we be certain about 'a'
> always being '1' when '++b' is evaluated; and 'a' always being '2' by
> the time '++c' is evaluated?") would hold?
Function calls are sequence points, i.e. calls boo() and goo() can not
be evaluated in parallel. Although it is still unknown which one gets
called first.
--
Max
Yes -- of course :-) It's so obvious after one gets some sleep :-)
> > Would one also be correct in thinking that rewriting the above as
>
> > int a;
> > int boo()
> > {
> > int b;
> > a = 1;
> > return ++b;
> > }
> > int goo()
> > {
> > int c;
> > a = 2;
> > return ++c;
> > }
> > int
> > main()
> > {
> > int d = boo() + goo();
> > return 0;
> > }
>
> > then the same answer to the above (i.e. "Can we be certain about 'a'
> > always being '1' when '++b' is evaluated; and 'a' always being '2' by
> > the time '++c' is evaluated?") would hold?
>
> Yes, behavior is UB again, but not because of the same reason. In this
> snippet, you read a non-initialized variable. There is however no change to
I think that's where my previous reply to myself (via c++etal
nickname) differs from your opinion... I would say 'No' -- the answer
would not be the same as for the 1st question... because the question
was not about defined vs undefined behavior for the whole of the code,
but rather about the state of 'a' (i.e. not concerning itself with
values of 'b' or 'c' -- only whether the value of 'a' is guaranteed to
be known by the time '++b' and '++c' are evaluated)... and I think we
can be certain about the value of 'a' in both 'boo' and 'goo' -- due
to non-interleaving functions characteristic (?)
My main thing which I had completely missed when I posted my 1st
message was that functions do not interleave -- such a basic oversight
had led me to convoluted 'use-case' scenarios and making stupid posts,
etc...
W.r.t. to accessing non-initialized variable: did you mean 'b' and
'c'? If that's the case, then I'd say that both snippets (2nd one with
'boo' and 'goo' functions; and the 1st one with declaring int b, c in
the 'main') would produce access to non-initialized 'b' and
'c' (?) ... but that was not really the point of the questions...
otherwise, sequence points or not, both snippets would exhibit
undefined behavior without any need for talking about sequence points
in the first place :-)
Good point that this happened in both snippets :) Anyway, i certainly agree
with you that apart from the uninitialized access, *the code is fine*. I
explicitly say "but *not* because of the same reason". :) My analysis ends
as with your analysis: function calls do not interleave :)