tricky assignment statemenent

C

ccwork

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.
 
C

Chris Torek

[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
replying said:
into p, as you explained, but it is _also_ read to determine at which

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;

as if it read:

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
code may cause your fingers. :)
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).
 
C

Christian Bau

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" ?
 
L

Lawrence Kirby

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

....
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;

as if it read:

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top