473,796 Members | 2,460 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Multiple Assignment Evaluation Debate

Hi All,

A coworker and I have been debating the 'correct' expectation of
evaluation for the phrase a = b = c. Two different versions of GCC
ended up compiling this as b = c; a = b and the other ended up
compiling it as a = c; b = c. (Both with no optimizations enabled).
How did we notice you may ask? Well, in our case 'b' was a memory
mapped register that only has a select number of writable bits. He
claims it has been a 'C Standard' that it will be evaluted as a = c; b
= c. I personally believe that it would make more sense for it to be
evaluated as b = c; a = b, although I would never write code that has a
questionable operation. Can anyone settle this debate?

Mar 10 '06
77 4763

"pete" <pf*****@mindsp ring.com> wrote in message
news:44******** ***@mindspring. com...
Robin Haigh wrote:
Trouble is, an enthusiastic reading of 6.5/2 can make all
sorts of things UB, including *p++.


An enthusiastic reading of 6.5/2 should find the footnote:

70)
This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

Can you see how this footnote helps? I can't

--
RSH
Mar 15 '06 #41

Ben Pfaff wrote:
en******@yahoo. com writes:
Ben Pfaff wrote:
en******@yahoo. com writes:

> Any compiler that compiles p = p->next = q as storing into p
> before fetching p->next is simply broken. Operands are
> evaluated before the operator they're operands for, and
> operators are evaluated before they produce a value--that's
> just how C semantics work (in a C abstract machine of course).

Do you have any citations to back up your assertions?


"Evaluation of an expression may _produce_ side effects."

"[At sequence points,] all side effects of _previous_
evaluations shall be complete [...]."

"In the abstract machine, all expressions are evaluated
_as specified by the semantics_."


OK.
"[An operator] may specify an operation to be performed
(which _in turn_ may _yield a value_ [...], _produce_ a
side effect, or some combination thereof) [...]."


I don't see anything about ordering there.


Maybe in some imaginary world where words have no intrinsic
meaning. In _this_ world where the writing is a mixture of
informal and semi-formal English, the words used clearly say
something about ordering because of causality relationships.
"The syntax specifies the precedence of operators _in the
evaluation of_ an expression [...]."


Precedence != ordering.


Again, the word precedence implies something about
ordering because of the meaning of the word. The
root of precedence is precede.
"[Except ...], _the order of evaluation of subexpressions_
and _the order in which side effects take place_ are both
unspecified." (Not "order of A and B" but "order of A" and
"order of B".)


I don't think that typographical distinction is a good one to
hinge an argument on. "the order of" could be repeated just for
clarity of exposition. Even if the typography is significant
here, I don't think it gets you where you want to go.


Some people think that the standard says the ordering of any
events whatsoever between sequence points is completely
unconstrained. But that's not what it says. If you read
the defining paragraph for sequence points, you'll see that
sequence points are mentioned in relation to the relative
order of _side effects_. In the Semantics paragraphs there
never is a statement that side effects are unordered
relative to expression evaluations. On the contrary, it's
always side effects of _previous_ evaluations.

The standard takes pains to point out _in every case_ in the
various Semantics paragraphs each case where sequence points
come into play in determining (or not determing) ordering,
and it's always about side effects, nothing else. Since
trouble is taken to point out _exceptions_ to ordering
relationships, the clear implication is that other parts of
the standard use words with their normal sense of causality
and ordering relationships.

The sentence quoted above is just confirmation that the
standard intends to talk about (non-)ordering of side effects
relative to each other, and not relative to other events.
Keeping these in mind, read through section 6.5, noting
which paragraphs are marked "Semantics" . Expressions
are evaluated "as specified by the semantics".


OK. Let's look at section 6.15.6 "Assignment operators":

3 ... The side effect of updating the stored value of the
left operand shall occur between the previous and the
next sequence point.

4 The order of evaluation of the operands is
unspecified. ...

It seems pretty clear that both the order of evaluation of the
operands and the time at which the result is stored are both
rather unconstrained.


Only when read in isolation. When read in conjunction with
the other statements quoted above, since the evaluation
_produces_ the side effect, obviously the evaluation has to
come first.

Mar 17 '06 #42

pete wrote:
en******@yahoo. com wrote:
The order in which
_side effects_ take place is unspecified, but _some_
evaluation must precede _any_ side effect, because it is
evaluations that produce side effects.


It's possible for all evaluations to be completed
before any side effects take place.


Sure it is. What is _not_ possible is for any side
effect to precede the expression evaluation that
produces it. Did you miss the point of what I
was saying?
The "at any time"
in the comment above means relative to other side effects.


Hence we get OP's situation:
"A coworker and I have been debating the 'correct' expectation
of evaluation for the phrase a = b = c.
Two different versions of GCC ended up compiling this as
b = c; a = b
and the other ended up compiling it as
a = c; b = c. "


Yes, the situation _arose_ because the storing of a can
precede the storing of b. But the question the OP was
asking was about the semantics of the assignment operator.
When the side effects happen is part of those semantics,
but not the main point OP was asking about.

Mar 17 '06 #43

pete wrote:
en******@yahoo. com wrote:

Micah Cowan wrote:
Michael Mair <Mi**********@i nvalid.invalid> writes:

> Richard G. Riley schrieb:
> > On 2006-03-12, pete <pf*****@mindsp ring.com> wrote:
> >
> >> I'm coming around to thinking that 6.5 [#2] is relevant, and that
> >> p = p->next = q
> >>is undefined, and not just unspecified.
> > but
> > p=(p->next=q);
> > is fine? I hope .
>
> No. Whether you write
> a = b = c;
> or
> a = (b = c);
> does not change anything -- apart from clarifying your intent.
> You still are modifying p twice between sequence points

Well, no he's not.
But he's reading its prior value for purposes other
than to determine the value stored, so same deal.


Look again. Reading p is necessary to evaluate p->q = next,


No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_, which needed both operands. Evaluation includes
all the actions in the Semantics paragraph, which includes
starting the side effect of storing the value.

Mar 17 '06 #44
On Friday 17 March 2006 04:48, en******@yahoo. com opined (in
<11************ *********@i39g2 000cwa.googlegr oups.com>):

pete wrote:
en******@yahoo. com wrote:
>
> Micah Cowan wrote:
> > Michael Mair <Mi**********@i nvalid.invalid> writes:
> >
> > > Richard G. Riley schrieb:
> > > > On 2006-03-12, pete <pf*****@mindsp ring.com> wrote:
> > > >
> > > >> I'm coming around to thinking that 6.5 [#2] is relevant, and
> > > >> that p = p->next = q
> > > >>is undefined, and not just unspecified.
> > > > but
> > > > p=(p->next=q);
> > > > is fine? I hope .
> > >
> > > No. Whether you write
> > > a = b = c;
> > > or
> > > a = (b = c);
> > > does not change anything -- apart from clarifying your intent.
> > > You still are modifying p twice between sequence points
> >
> > Well, no he's not.
> > But he's reading its prior value for purposes other
> > than to determine the value stored, so same deal.
>
> Look again. Reading p is necessary to evaluate p->q = next,


No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_, which needed both operands. Evaluation includes
all the actions in the Semantics paragraph, which includes
starting the side effect of storing the value.


I think pete is right. The compiler _knows_ that the result of (p->q =
next) _will_be_ next before it even produces any code, and can use that
knowledge once it does get to producing some.

--
BR, Vladimir

How long a minute is depends on which side of the bathroom door you're
on.

Mar 17 '06 #45

Vladimir S. Oka wrote:
On Friday 17 March 2006 04:48, en******@yahoo. com opined (in
<11************ *********@i39g2 000cwa.googlegr oups.com>):

pete wrote:
en******@yahoo. com wrote:
>
> Micah Cowan wrote:
> > Michael Mair <Mi**********@i nvalid.invalid> writes:
> >
> > > Richard G. Riley schrieb:
> > > > On 2006-03-12, pete <pf*****@mindsp ring.com> wrote:
> > > >
> > > >> I'm coming around to thinking that 6.5 [#2] is relevant, and
> > > >> that p = p->next = q
> > > >>is undefined, and not just unspecified.
> > > > but
> > > > p=(p->next=q);
> > > > is fine? I hope .
> > >
> > > No. Whether you write
> > > a = b = c;
> > > or
> > > a = (b = c);
> > > does not change anything -- apart from clarifying your intent.
> > > You still are modifying p twice between sequence points
> >
> > Well, no he's not.
> > But he's reading its prior value for purposes other
> > than to determine the value stored, so same deal.
>
> Look again. Reading p is necessary to evaluate p->q = next,

No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_, which needed both operands. Evaluation includes
all the actions in the Semantics paragraph, which includes
starting the side effect of storing the value.


I think pete is right. The compiler _knows_ that the result of (p->q =
next) _will_be_ next before it even produces any code, and can use that
knowledge once it does get to producing some.


You've fallen into the trap of arguing based on what a
compiler might be capable of. Regardless of what the
compiler knows, it's still obliged to produce code that
behaves according to how the Semantics paragraphs and
everything else in the standard says it must.

Mar 17 '06 #46
On Friday 17 March 2006 15:27, en******@yahoo. com opined (in
<11************ **********@j52g 2000cwj.googleg roups.com>):

Vladimir S. Oka wrote:
On Friday 17 March 2006 04:48, en******@yahoo. com opined (in
<11************ *********@i39g2 000cwa.googlegr oups.com>):
>
> pete wrote:
>> en******@yahoo. com wrote:
>> >
>> > Micah Cowan wrote:
>> > > Michael Mair <Mi**********@i nvalid.invalid> writes:
>> > >
>> > > > Richard G. Riley schrieb:
>> > > > > On 2006-03-12, pete <pf*****@mindsp ring.com> wrote:
>> > > > >
>> > > > >> I'm coming around to thinking that 6.5 [#2] is relevant,
>> > > > >> and that p = p->next = q
>> > > > >>is undefined, and not just unspecified.
>> > > > > but
>> > > > > p=(p->next=q);
>> > > > > is fine? I hope .
>> > > >
>> > > > No. Whether you write
>> > > > a = b = c;
>> > > > or
>> > > > a = (b = c);
>> > > > does not change anything -- apart from clarifying your
>> > > > intent. You still are modifying p twice between sequence
>> > > > points
>> > >
>> > > Well, no he's not.
>> > > But he's reading its prior value for purposes other
>> > > than to determine the value stored, so same deal.
>> >
>> > Look again. Reading p is necessary to evaluate p->q = next,
>>
>> No, it isn't.
>> The value of (p->q = next) is (next)
>
> The value of p->q = next is next. But in order to get the
> value, the assignment p->q = next must _have been
> evaluated_, which needed both operands. Evaluation includes
> all the actions in the Semantics paragraph, which includes
> starting the side effect of storing the value.


I think pete is right. The compiler _knows_ that the result of (p->q
= next) _will_be_ next before it even produces any code, and can use
that knowledge once it does get to producing some.


You've fallen into the trap of arguing based on what a
compiler might be capable of. Regardless of what the
compiler knows, it's still obliged to produce code that
behaves according to how the Semantics paragraphs and
everything else in the standard says it must.


But it still does not evaluate p->q in order to assign next to it. What
is evaluated is next, and its value is /assigned/ to p->q. Next, the
assignment is evaluated and assigned to p. The assignment evaluates to
next, but I don't think that compiler is obliged to do that in any
particular way.

--
BR, Vladimir

Writing about music is like dancing about architecture.
-- Frank Zappa

Mar 17 '06 #47
[on whether
p = p->next = next;
could have undefined behavior]
Vladimir S. Oka wrote:
I think pete is right. The compiler _knows_ that the result of (p->q =
next) _will_be_ next before it even produces any code, and can use that
knowledge once it does get to producing some.

In article <11************ **********@j52g 2000cwj.googleg roups.com>
<en******@yahoo .com> wrote:You've fallen into the trap of arguing based on what a
compiler might be capable of. Regardless of what the
compiler knows, it's still obliged to produce code that
behaves according to how the Semantics paragraphs and
everything else in the standard says it must.


This is correct -- in order to claim to compile Standard C, a C
compiler must obey the standard -- but the question is whether
"everything else in the standard" actually *says* that

p = p->next = next;

has to have defined behavior. You and I may think it is bizarre
and wrong if the actual wording in the Standard fails to require
this to work the "obvious" and "correct" way. Unfortunately, those
who argue that both C89 and C99 fail to require this to work, do
in fact seem to have a leg to stand on, as the saying goes.

(The standard has a number of defects, and I consider this to be
one of them, albeit a minor one. Someone's -- I have forgotten
whose -- proposed annex to the C99 standard, with a formal
model for deciding sequence points, would have at least provided
a definitive answer. But that annex did not make it in.)

(There is a simple cure available to the C programmer, though: just
write:

p->next = next, p = next;

instead. We can avoid skating on the thin ice, instead of arguing
about just how thin it may be.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Mar 17 '06 #48
en******@yahoo. com writes:
pete wrote:
No, it isn't.
The value of (p->q = next) is (next)


The value of p->q = next is next. But in order to get the
value, the assignment p->q = next must _have been
evaluated_,


Wrong. The assignment itself need not have taken place. If you really
/did/ understand sequence points, you would know this.

As far as C is concerned, an implementation is more than welcome to do

p = next;
p->q = next;

That's why sequence points are very important.
Mar 17 '06 #49

In article <87************ @benpfaff.org>, Ben Pfaff <bl*@cs.stanfor d.edu> writes:
You (Robin Haigh) believe that
p = p->next = q;
is well defined. Many other people share this opinion. But when
it was brought up in comp.std.c a long time ago, there were also
many people with the opposite opinion. If I recall correctly,
some of these folks were actually committee members.


It's my feeling that any question of the C standard which leads to
an extended argument between Lawrence Kirby and Douglas Gwyn[1] is
pretty much by definition an unclear matter.

I agree with Ben. It's not productive. Avoid multiple assignments
between sequence points where ordering could be significant, and not
only is the potential problem avoided, but the resulting code will
be simpler and clearer.
1. http://groups.google.com/group/comp....ab46d713d239a2

--
Michael Wojcik mi************@ microfocus.com

Do not "test" parts, as this may compromise sensitive joinery. Those who
suffer difficulty should abandon the enterprise immediately. -- Chris Ware
Mar 18 '06 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.