[comp.lang.c] evaluation order

chris@mimsy.UUCP (Chris Torek) (09/09/89)

>>In article <149@cpsolv.UUCP> rhg@cpsolv.UUCP (Richard H. Gumpertz) writes:
>>>The exchange of x and y that has been under discussion:
>>>	x ^= y ^= x ^= y
>>>is non-portable because it depends on right-to-left evaluation which is NOT
>>>specified in the C standard.

This is correct.

>In article <1400@levels.sait.edu.au> CCDN@levels.sait.edu.au (DAVID NEWALL) writes:
>>I think it is specified.  (Perhaps it depends on whose standard you follow?)

No, it is not specified.

>>K&R I, page 19:
>>    ... an assignment has a value and assignments associate right to left."

In article <1007@m3.mfci.UUCP> karzes@mfci.UUCP (Tom Karzes) writes:
>No, it is not specified.  The K&R example is merely pointing out that the
>assignment is parsed as:
>
>    nl = (nw = (nc = 0));

Tom is correct.

We have two separate concepts here.  The one to which K&R p. 19 refers
is *grouping*; grouping is affected by *precedence* and *associativity*.
(Parentheses are a syntactic construct that---at least in Classic C---serve
only to give specific precedence: the highest precedence that exists.)
The concept we have to worry about in the `obfuscated swap' above is
*evaluation order*.

It is easy to see that evaluation order and grouping differ.  Consider
the expression

	a + b

This has no grouping (there is only one operator, hence nothing to group
it with), but does have order of evaluation (do we inspect `b' first, or
`a'?).  Precedence and associativity come into play only when there are
multiple operators:

	a + b * c + d

If an expression has two or more of a single operator `in a row', as in

	a + b + c

we apply the associativity rule (here `left associative') to decide
whether the result should be `add a to result of adding b and c' or
`add c to result of adding a and b'.  When two different operators
mingle, their precedence determines the result.  `*' is `higher' than
`+', so a+b*c+d means `add d to sum of result of b*c and a'.

In some languages, grouping and/or parentheses determine evaluation
order as well; but in classic C, they do neither.  The proposed
standard makes parentheses force a limited amount of evaluation order
under certain circumstances, although deciding exactly when you can
get away with what can be difficult.

In any case,

	a + b

can be done as either `fetch b, fetch a, add' or `fetch a, fetch b, add'.
Normally, the result is identical, so the evaluation order does not matter.

Similar reasoning applies to

	x ^= y ^= x ^= y;

We have lots of choices in implementing this, but this time, some of them
do matter:

>When evaluating a ^= b, the compiler may generate any of the following:
>
>    1.  evaluate a, evaluate b, xor, assign
>    2.  evaluate b, evaluate a, xor, assign
>    3.  some hybrid of 1 and 2
>
>If it chooses the first sequence for the outer assignment in the original
>^= example, the example will fail.

The draft standard includes the concept of `sequence points', which helps
to answer questions about evaluation order.  Sequence points are, in
effect, `places where everything gets written down'.  There are no
sequence points in x^=y^=x^=y.  We can add one:

	x ^= y, x ^= y ^= x;

and then enumerate all the possible evaluation orders to decide whether
that sequence point is sufficient to guarantee the expected result.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

bobc@attctc.Dallas.TX.US (Bob Calbridge) (09/14/89)

Is there any way to guarantee the order in which certain functions are
evaluated?  By way of example, if I wanted to avoid the replication of 
of strlen() in the following example:

if (write(handle, buf, strlen(buf)) != strlen(buf)) do_something();

by using rephrasing it like:

if (write(handle, buf, len=strlen(buf)) != len) do_something();

can I be assured that 'len' will be assigned the length of 'buf' before it
is used on the right side of the comparison operator.  I understand that
some optimizing compilers may do some odd re-arranging and I'm worried that
the value of 'len' before excuting this line of code may be used on the
right side.  Is this really possible?  Are there any assurances?

I know that I can try this with my compiler and some test code but would it
be portable?

thanks,
Bob
-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=             I know it's petty..........                                     =
-                  But I have to justify my salary!                           -
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/14/89)

In article <9361@attctc.Dallas.TX.US> bobc@attctc.Dallas.TX.US (Bob Calbridge) writes:
>if (write(handle, buf, len=strlen(buf)) != len) do_something();
>can I be assured that 'len' will be assigned the length of 'buf' before it
>is used on the right side of the comparison operator.

No.
Either side of != may be evaluated first, depending on the implementation.
It's best to split such multiple actions into separate statements;
you don't get any extra credit for complexity of the expression.

jdr+@andrew.cmu.edu (Jeff Rosenfeld) (09/14/89)

> Excerpts from netnews.comp.lang.c: 14-Sep-89 evaluation order Bob
> Calbridge@attctc.Dal (1134)

> By way of example, if I wanted to avoid the replication of 
> of strlen() in the following example:

> if (write(handle, buf, strlen(buf)) != strlen(buf)) do_something();

> by using rephrasing it like:

> if (write(handle, buf, len=strlen(buf)) != len) do_something();


What's wrong with
	len = strlen(buf);
	if (write(handle,buf,len) != len) do_something();
?

Just because C lets you do funky things doesn't mean that you have to do
them all the time. If you really want to do it in one statement you can:

	len=strlen(buf), write(handle,buf,len) != len ? do_something() : 0 ;

But hopefully you'd rather not.
			- Jeff.

ark@alice.UUCP (Andrew Koenig) (09/14/89)

In article <9361@attctc.Dallas.TX.US>, bobc@attctc.Dallas.TX.US (Bob Calbridge) writes:

> if (write(handle, buf, len=strlen(buf)) != len) do_something();

> can I be assured that 'len' will be assigned the length of 'buf' before it
> is used on the right side of the comparison operator.

No you can't.

However, you can be assured if you write it this way:

	len = strlen(buf);
	if (write(handle, buf, len) != len) do_something();

Is this so terrible?

You can even write it this way:

	if (len = strlen(buf), write(handle, buf, len) != len) do_something();

but I far prefer the previous way.
-- 
				--Andrew Koenig
				  ark@europa.att.com

cpcahil@virtech.UUCP (Conor P. Cahill) (09/14/89)

In article <9361@attctc.Dallas.TX.US>, bobc@attctc.Dallas.TX.US (Bob Calbridge) writes:
> Is there any way to guarantee the order in which certain functions are
> evaluated?  By way of example, if I wanted to avoid the replication of 
> of strlen() in the following example:
> 
> if (write(handle, buf, strlen(buf)) != strlen(buf)) do_something();
> 
> by using rephrasing it like:
> 
> if (write(handle, buf, len=strlen(buf)) != len) do_something();
> 
How about 
	len = strlen(buf);
	if( write(...,len) != len)...

> can I be assured that 'len' will be assigned the length of 'buf' before it
> is used on the right side of the comparison operator.  I understand that

nope.

> some optimizing compilers may do some odd re-arranging and I'm worried that
> the value of 'len' before excuting this line of code may be used on the
> right side.  Is this really possible?  Are there any assurances?

There are no assurances as to the time the left or right side of the != are
evaluated, nor to the time at which the assignment takes place (unless a
sequence point has been reached).

> I know that I can try this with my compiler and some test code but would it
> be portable?

Nope.





-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

henry@utzoo.uucp (Henry Spencer) (09/14/89)

In article <9361@attctc.Dallas.TX.US> bobc@attctc.Dallas.TX.US (Bob Calbridge) writes:
>if (write(handle, buf, len=strlen(buf)) != len) do_something();
>
>can I be assured that 'len' will be assigned the length of 'buf' before it
>is used on the right side of the comparison operator...

There is a sequence point at the function call, but it doesn't save you
because you don't know which operand of != gets evaluated first.  In
general this sort of thing isn't very safe.  Better would be:

	len=strlen(buf);
	if (write(handle, buf, len) != len) do_something();

Is there some reason why you can't just write it that way?

As in APL, C "one-liners" are a perverse art form, suitable for presentation
to the Obfuscated C Contest but usually inappropriate in production code.
-- 
V7 /bin/mail source: 554 lines.|     Henry Spencer at U of Toronto Zoology
1989 X.400 specs: 2200+ pages. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

bobc@attctc.Dallas.TX.US (Bob Calbridge) (09/15/89)

In article <UZ3ta3_00XcAI4hY08@andrew.cmu.edu>, jdr+@andrew.cmu.edu (Jeff Rosenfeld) writes:
> > Excerpts from netnews.comp.lang.c: 14-Sep-89 evaluation order Bob
> > Calbridge@attctc.Dal (1134)
> 
> > By way of example, if I wanted to avoid the replication of 
> > of strlen() in the following example:
> 
> > if (write(handle, buf, strlen(buf)) != strlen(buf)) do_something();
> 
> > by using rephrasing it like:
> 
> > if (write(handle, buf, len=strlen(buf)) != len) do_something();
> 
> 
> What's wrong with
> 	len = strlen(buf);
> 	if (write(handle,buf,len) != len) do_something();
> ?
> 
> Just because C lets you do funky things doesn't mean that you have to do
> them all the time. If you really want to do it in one statement you can:
> 
> 	len=strlen(buf), write(handle,buf,len) != len ? do_something() : 0 ;
> 
> But hopefully you'd rather not.
> 			- Jeff.

As I said, this was by way of example.  I reduced it to a simpler form of
the real structure I wanted to consider.  To wit

while (((ch=getch()) != CR) && (ch != LF)) {
	doitoit()
	doitagain();
	doitlasttime();
}

I did a simple routine that I use often called

	ynget (int row, int column, char *prompt)    that basically
looked like this:

	gotoxy (row, column);
	puts (prompt);
	do {
		ch =  toupper(getch());
	} while ((ch != 'Y' && (ch != 'N'));
	return (ch == 'Y');

where I figured that it would have been simpler to do something like

	while (((ch = toupper(getch())) != 'Y') && (ch !='N'));

Well, not necessarily simpler, but more compact.  I don't know if this
would necessarily result in shorter object code or faster but it wouldn't 
matter if I couldn't trust the evaluation order.

Having read that && is a short circuit operator this may not be the precise
example to make clear what I'm looking at but I think it gets the major point
across.
-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=             I know it's petty..........                                     =
-                  But I have to justify my salary!                           -
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=