# tricky assignment statemenent

Discussion in 'C Programming' started by ccwork, Jan 17, 2005.

1. ### ccworkGuest

>There are two assignments here. In one assignment, p is modified. The
>prior value of p is arguably used to determine the new value stored

into
>p, as you explained, but it is _also_ read to determine at which

memory
>location the second assignment will happen, so it is not _only_ read

to
>determine the value stored, therefore undefined behavior.

There is something wrong. The first assignment is "p->next = q" and
"p" is _not_ modified. After this assignment value of "p" is _not_
changed; only "p->next" is changed. The second assignemnt is "p =
p->next =q" and "p" is going to hold the result of "p->next = q",
which is "q".

Consider "b = b * 10". According to your logic it will be undefined
since b is read to determine new value but also read to determine
memory for second assignment.

ccwork, Jan 17, 2005

2. ### Chris TorekGuest

[given "p = p->next = q" for suitable pointers p and q]

Someone -- name filed off but not by me and the person to whom I am

>>There are two assignments here. In one assignment, p is modified. The
>>prior value of p is arguably used to determine the new value stored

>into p, as you explained, but it is _also_ read to determine at which
>>memory location the second assignment will happen, so it is not
>>_only_ read to >determine the value stored, therefore undefined behavior.

In article <>
ccwork <> wrote:
>There is something wrong. The first assignment is "p->next = q" and
>"p" is _not_ modified.

This is correct, except that the word "first" is not appropriate --
there is no ordering implied yet.

>After this assignment value of "p" is _not_ changed; only "p->next"
>is changed. The second assignemnt is "p = p->next =q " and "p" is
>going to hold the result of "p->next = q", which is "q".

Yes. The problem comes about because (or "if", depending on how
you read the precise text of the C89 and C99 standards) the words
"before" and "after" are not applicable. There are those who
claim that a C compiler can treat:

a = b = c;

temp = c;
a = temp;
b = temp;

i.e., assign to the leftmost object, then assign to the middle
object.

Suppose this happens with "p = p->next = q". Then we get:

temp = q;
p = temp;
p->next = temp;

which does something quite different from:

temp = q;
p->next = temp;
p = temp;

If you believe that the C standard allows this runtime order of
operations, then the assignment "p = p->next = q" is undefined
and sometimes does the wrong thing. If you believe that the C
standard does not allow this runtime order of operations, then
the assignment is well-defined and always does the right thing.

While it would be very nice to say "clearly the folks who wrote
the standard *meant* to say it is well-defined", we do not get to
do that. We have to read what it actually says. Only the Anointed
Few who have authority to respond to Defect Reports can say
"this is what it means".

Since it is not clear, your best bet is to avoid the construct --
if you write:

p->next = q;
p = q; /* or p = p->next; */

your code will absolute, positively work every time. This is
probably worth the extreme exhaustion typing that extra line of

>Consider "b = b * 10". According to your logic it will be undefined
>since b is read to determine new value but also read to determine
>memory for second assignment.

This assignment is not very analagous; a better comparison might
be something like:

b = (b = b * 10) + 4;

except this is considerably worse than "p = p->next = q" (the case
with "b" here is clearly undefined, while the case with p is not
clear at all).
--
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
Reading email is like searching for food in the garbage, thanks to spammers.

Chris Torek, Jan 17, 2005

3. ### Christian BauGuest

In article <>,
(ccwork) wrote:

> >There are two assignments here. In one assignment, p is modified. The
> >prior value of p is arguably used to determine the new value stored

> into
> >p, as you explained, but it is _also_ read to determine at which

> memory
> >location the second assignment will happen, so it is not _only_ read

> to
> >determine the value stored, therefore undefined behavior.

>
> There is something wrong. The first assignment is "p->next = q" and
> "p" is _not_ modified. After this assignment value of "p" is _not_
> changed; only "p->next" is changed. The second assignemnt is "p =
> p->next =q" and "p" is going to hold the result of "p->next = q",
> which is "q".
>
> Consider "b = b * 10". According to your logic it will be undefined
> since b is read to determine new value but also read to determine
> memory for second assignment.

Where is the "second assignment" ?

Christian Bau, Jan 17, 2005
4. ### Lawrence KirbyGuest

On Mon, 17 Jan 2005 05:16:19 +0000, Chris Torek wrote:

....

>>After this assignment value of "p" is _not_ changed; only "p->next"
>>is changed. The second assignemnt is "p = p->next =q " and "p" is
>>going to hold the result of "p->next = q", which is "q".

>
> Yes. The problem comes about because (or "if", depending on how
> you read the precise text of the C89 and C99 standards) the words
> "before" and "after" are not applicable. There are those who
> claim that a C compiler can treat:
>
> a = b = c;
>
>
> temp = c;
> a = temp;
> b = temp;
>
> i.e., assign to the leftmost object, then assign to the middle
> object.

I was just looking back at this, and IMHO it isn't quite as simple as that.
I would represent it as the following with & indicating "lvalue of" and *
"object designated by"

temp1 = c; /* Evaluation of operand c */
tempb = &b; /* Evaluation of operand b */
tempa = &a; /* Evaluation of operand a */
temp2 = temp1; /* Result of b = c */
*tempa = temp2; /* Execution of assignment to a */
*tempb = temp1; /* Execution of assignment to b */

I have no problem with *tempa = temp2 preceding *tempb = temp1. What I
don't accept is that *tempa = temp2 can precede tempb = &b, because
temp2 = temp1 cannot. Essentially you cannot execute an operator in the
abstract machine before you have evaluated its operands.

Lawrence

Lawrence Kirby, Feb 3, 2005