[net.lang.c] order of evaluation of expression

dave@murphy.UUCP (10/10/86)

Well, gang, I just tried this code on our Gould UTX/32 C compiler:

main()
{
	int a=0, b=0;
	a = ((b=1),b) + ((b=2,b) + ((b=3),b);
	printf("%d %d\n",a,b);
	a = (b=1) + (b=2) + (b=3);
	printf("%d %d\n",a,b);
}

and got:

9 3
6 3

So, let's do some interpreting and reading-between-the-lines.  I think that
there are a couple of points that a lot of people are confused on, regarding
these two expressions:

1. Although the comma operator guarantees that its left operand will be eval-
uated before its right operand, it does not guarantee that its left operand
will be evaluated before the left operand of some other comma expression
in the same statement.

2. The expression of the = operator is its right operand; however, K&R states
on p. 50, second paragraph from the bottom, that "when side effects (assign-
ments to actual variables) takes place is left to the discretion of the
compiler..."  This can, and often has, been interpreted to mean that the
assignment is *not necessarily done at the time that the = expression is
evaluated*.  This is an important point that I think a lot of people miss
when they try to figure out when a side effect takes effect; it is possible
that the assigment may not be done until a later statement references the
variable.  (Optomizing compilers do this sort of thing a lot.)

So, let's look at the two statments above.  I claim that the first is
faulty code and can legitimately produce *any value whatsoever*.  Here's
why: when the comma expressions are evaluated, the assignment on the
left is done first, but by point #2, the assigment may not be done at
this time.  If not, when the right operand is evaluated, the value of b
previous to the statement may be used, and if this is done in all three
of the comma expressions, and if the previous value was 6409, then a
could turn out being 19227! (In fact, I believe that with some
compilers, declaring b as a register variable could alter the result.)
Note also that since the order of the side effects is unspecified, b may
have any of the values 1, 2, or 3 after the statement is executed. 

The second computation, on the other hand, had better evaluate to 6.  Why?
Because in this case the expression value of the = operator is what is
being used, rather than the value of the side effect.  If it comes out
different, then the compiler is not evaluating = operators correctly.
Note, however, that the value of b after the expression is executed can
still be any of 1, 2, or 3.

The real moral of this story is that you shouldn't do more than one assignment
to a variable in an expression, and you shouldn't use the assigned-to variable
elsewhere in the expression (although using the expression value of the
assignment is okay).  The same applies to ++, --, and function calls.
---
It's been said by many a wise philosopher that when you die and your soul
goes to its final resting place, it has to make a connection in Atlanta.

Dave Cornutt, Gould Computer Systems, Ft. Lauderdale, FL
UUCP:  ...{sun,pur-ee,brl-bmd}!gould!dcornutt
 or ...!ucf-cs!novavax!houligan!dcornutt
ARPA: wait a minute, I've almost got it...

"The opinions expressed herein are not necessarily those of my employer,
not necessarily mine, and probably not necessary."

harald@kvvax4.UUCP (Harald Eikrem) (10/16/86)

dave@murphy.UUCP (Dave Cornutt) writes:
>Well, gang, I just tried this code on our Gould UTX/32 C compiler:
>
>main()
>{
>	int a=0, b=0;
>	a = ((b=1),b) + ((b=2,b) + ((b=3),b);
>	printf("%d %d\n",a,b);
>	a = (b=1) + (b=2) + (b=3);
>	printf("%d %d\n",a,b);
>}
>
>and got:
>
>9 3
>6 3

With the Ultrix 1.1 (BSD4.2) compiler you would have seen:
9 3
7 3

Explain anyone?

Case 1 is demonstrated by:
	int a,b,c,d,e;
	a = (b=1,c=b) + (b=2,d=b) + (b=3,d=b);
	printf("%d %d %d %d %d\n",a,b,c,d,e);

9 3 3 3 3

To me, it turns more weird if I say:
	a = (b=1,c=b,b) + (b=2,d=b,b) + (b=3,e=b,b);
	printf("%d %d %d %d %d\n",a,b,c,d,e);

and out comes:
9 3 1 2 3

Parentheses to pair expressions around comma operators make no difference.


>The real moral of this story is that you shouldn't do more than one assignment
>to a variable in an expression, and you shouldn't use the assigned-to variable
>elsewhere in the expression (although using the expression value of the
>assignment is okay).  The same applies to ++, --, and function calls.

Clearly.
-- 

   ...!mcvax!kvvax4!harald      -=-=-=-=<  Harald E  >=-=-=-=-