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! - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=