tomc@oakhill.UUCP (Tom Cunningham) (09/06/86)
Sorry if this topic has been overly exercised already. In the following code fragment: /* a = b + b + b */ a = ((b=1),b) + ((b=2),b) + ((b=3),b) I expected the result to be 6. With the Microsoft C compiler and the compiler on the Sun 3, the result is 9. Apparently the parenthetical assignments are all getting done before the comma and addition. Any thoughts on thi Tom Cunningham "Good, fast, cheap -- select two." USPS: Motorola Inc. 6501 William Cannon Dr. W. Austin, TX 78735-8598 UUCP: {ihnp4,seismo,ctvax,gatech}!ut-sally!oakhill!tomc Phone: 512-440-2953
eectrsef@titan.UUCP ( SA User Serv.) (09/19/86)
In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: > /* a = b + b + b */ > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > >I expected the result to be 6. With the Microsoft C compiler and the >compiler on the Sun 3, the result is 9. Apparently the parenthetical >assignments are all getting done before the comma and addition. Any >thoughts on this? > Tom, I agree, the result should be 6, as defined by K&R, but I have tried it on a Cyber 180/830 running NOS VE, and get 9, also AT&T's 3B5 System V, gets 9, But A copy of the Small-C Compiler that I have ported comes up with a 6. Does this seam to imply that Small-C is a better (more accurate) compiler, than those that AT&T produces? I find it totally unaccepable that AT&T can not produce a working C compiler. I would like everyone to test it on as many machines as prossible, to see if we can find as least ONE other besides Small-C, that works. Mike Stump ucbvax!hplabs!csun!csunb!beusemrs
jason@hpcnoe.UUCP (Jason Zions) (09/23/86)
> / tomc@oakhill.UUCP (Tom Cunningham) / 4:16 pm Sep 5, 1986 / > Sorry if this topic has been overly exercised already. In the following > code fragment: > > /* a = b + b + b */ > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > [ Wants result to be 6; his micro compiler does that, his big system compiler produces 9. Doesn't know if it's a bug. ] > Tom Cunningham "Good, fast, cheap -- select two." > UUCP: {ihnp4,seismo,ctvax,gatech}!ut-sally!oakhill!tomc Sorry. K&R does guarantee that the left side of a comma operator will be evaluated sometime before the right side of the operator, but does not say ANYTHING about interleaving evaluations of other expressions. This was covered about a month ago, but not quite in the same context. The upshot of it all was that interleaving of expression evaluation is indeed legal, and some compilers (4.2BSD, I believe, is a notorious example) are known to do so. "Doctor, Doctor, I get bit every time I use multiple side-effects in the same statement!" "So don't do that!" -- This is not an official statement of Hewlett-Packard Corp., and does not necessarily reflect the views of HP. It is provided completely without warranty of any kind. Lawyers take 3d10 damage and roll a saving throw vs. ego attack. Jason Zions Hewlett-Packard Colorado Networks Division 3404 E. Harmony Road Mail Stop 102 Ft. Collins, CO 80525 {ihnp4,seismo,hplabs,gatech}!hpfcdc!hpcnoe!jason
david@ztivax.UUCP (09/23/86)
On Ultrix V1.2 (4.3bsd, more or less), the answer is... NINE! oops...
drw@cullvax.UUCP (Dale Worley) (09/24/86)
> In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: > > /* a = b + b + b */ > > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > > > >I expected the result to be 6. With the Microsoft C compiler and the > >compiler on the Sun 3, the result is 9. Apparently the parenthetical > >assignments are all getting done before the comma and addition. Any > >thoughts on this? Harbison&Steele (7.11) makes it clear that an implementation must evaluate one argument of a binary operator completely before starting evaluation of the other argument. Thus, the result should be 6. I don't know what the ANSI standard says. Dec VAX Ultrix gives 9. Lattice C 3.00 for MS-DOS gives 7!!! (Yes, that's "7", not a typo!) Dale
donn@utah-cs.UUCP (Donn Seeley) (09/25/86)
I sure thought that someone would finally read the manual and see where the 'problem' was, but I guess I was wrong... Section 7 of the C reference manual: '... [T]he order of evaluation of expressions is undefined,' except in specific cases: '&&', '||', ',' and '?'. These cases together with the precedence rules define a partial ordering on evaluations. Let's look at an example: a = ((b=1),b) + ((b=2),b) + ((b=3),b) 1 2 3 4 5 6 7 8 9 I've numbered the operators in the expression to indicate the subexpressions. Here is the transitive closure of the set of ordered pairs which defines the partial ordering: <2,1> <2,4> <3,4> <5,1> <5,6> <6,1> <6,7> <8,1> <8,9> <9,7> <2,3> <3,1> <4,1> <5,4> <5,7> <6,4> <7,1> <8,7> <9,1> (Notice that '[e]xpressions involving a commutative and associative operator ... may be rearranged arbitrarily', which actually reduces the number of orderings -- <4,7> isn't in the set for this reason.) Notice that <2,5>, <2,8> and <5,8> are not in the set; the expressions 2, 5, and 8 ('b=1', 'b=2' and 'b=3') may be evaluated in any order. Thus 'a' may have any value between 3 and 9, inclusive, after this statement is executed. Actually my favorite order-of-evaluation bug appeared in some poor user's code to add an array of N ints: int array[N] = { ... }; int *R = &array[0]; int sum = *R++ + *R++ + *R++ + *R++ + *R++ + ... + *R++; This worked (believe it... or not!) with the Ritchie compiler on the PDP11 and failed miserably under the PCC on a VAX. Wondering what code Lattice C generated to get a == 7, Donn Seeley University of Utah CS Dept donn@utah-cs.arpa 40 46' 6"N 111 50' 34"W (801) 581-5668 decvax!utah-cs!donn PS -- I suppose you've noticed that I've oversimplified the treatment of 4 and 7 in the example, since the commutative/associative rule causes an ambiguity (e.g. 3 must be done before one of 4 or 7, since 3 may be reordered under 7 in the expression tree)...
mwm@eris.berkeley.edu (Mike Meyer) (09/26/86)
In article <353@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes: >> In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: >> > /* a = b + b + b */ >> > a = ((b=1),b) + ((b=2),b) + ((b=3),b) >> > >> >I expected the result to be 6. With the Microsoft C compiler and the >> >compiler on the Sun 3, the result is 9. Apparently the parenthetical >> >assignments are all getting done before the comma and addition. Any >> >thoughts on this? > >Harbison&Steele (7.11) makes it clear that an implementation must >evaluate one argument of a binary operator completely before starting >evaluation of the other argument. Thus, the result should be 6. I >don't know what the ANSI standard says. My reading of the ANSI hardcopy is that it doesn't say. I thought H&S was a description, not a definition. >Dec VAX Ultrix gives 9. As do VAX 4.2 and 4.3. >Lattice C 3.00 for MS-DOS gives 7!!! (Yes, that's "7", not a typo!) Some messy - and almost believable - arguments can be made that the value of that expression is "implementation dependent". Rather than do that, I'll just point out that *ANY* time++ you have a single statement that changes a variable, then uses the variable in a different place, you're asking for trouble. For that particular expression, I'd expect the following, with increasing surprise as you move down the list: 6 3, 9 4, 5, 7, 8 other integers representable on the machine NANs of various flavors dropped cores. <mike ++ Except for those cases that are in different operands of a logical operator, as the evaluation order on those is known.
tom@hcrvx1.UUCP (Tom Kelly) (09/26/86)
In article <3926@utah-cs.UUCP> donn@utah-cs.UUCP (Donn Seeley) discusses
the example:
a = ((b=1),b) + ((b=2),b) + ((b=3),b)
showing the partial order induced by the expression evaluation rules
of C language (as defined in K & R) and how various orders of
evaluation of the side effects are compatible with that partial
order. His conclusion is that the "correct" answer is an integer
between 3 and 9 inclusive. Various other people have posted the
answers obtained by various compilers.
The ANSI C committee (X3J11) has considered this question at some
length, mostly in the context of being able to write safe macros
that involve side-effects (prototypical example: getchar() + getchar().
Can the evaluation of the ?: operators in the "usual" implementation
of getchar be interleaved?).
The current draft (86-098: 9 July 1986) specifies in section 3.3 Expressions
(p. 31):
Except as indicated by the syntax, or otherwise specified
later (for the function-call operator (), the unary plus
operator, &&, ||, ?: and comma operators), the order
of evaluation of an expression is unspecified. The
implementation may evaluate subexpressions in any order,
even if the subexpressions produce side effects. The
order in which side effects take place is unspecified,
except that the evaluation of the operands of an
operator that involves a sequence point shall not be
interleaved with other evaluations.
Section 3.3.17 Comma Operator (p. 46)
The left operand of a comma operator is evaluated as a
void expression; there is a sequence point after its
evaluation. Then the right operand is evaluated; the
result has its type and value.
This has the result (along with the definition of sequence point) of
specifying that the value of "a" will be 6, since once one of the
comma expressions is started, it must be fully evaluated before any
of the others are. Of course, the resulting value of "b" is still
either 1, 2 or 3.
Tom Kelly (416) 922-1937
Human Computing Resources Corp.
{utzoo, ihnp4, decvax}!hcr!tom
gbm@galbp.UUCP (Gary McKenney) (09/26/86)
> In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: > > /* a = b + b + b */ > > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > > > >I expected the result to be 6. With the Microsoft C compiler and the > >compiler on the Sun 3, the result is 9. Apparently the parenthetical > >assignments are all getting done before the comma and addition. Any > >thoughts on this? > > > Tom, I agree, the result should be 6, as defined by K&R, but I have tried > it on a Cyber 180/830 running NOS VE, and get 9, also AT&T's 3B5 > System V, gets 9, But A copy of the Small-C Compiler that I have ported > comes up with a 6. Does this seam to imply that Small-C is a better > (more accurate) compiler, than those that AT&T produces? I find it > totally unaccepable that AT&T can not produce a working C compiler. > I would like everyone to test it on as many machines as prossible, to > see if we can find as least ONE other besides Small-C, that works. > > Mike Stump ucbvax!hplabs!csun!csunb!beusemrs You are both wrong. All expressions in lowest set of parenthesis are evaluated first from left to right, therefore before any addition occurs b = 3. a = 3 + 3 + 3; gbm
jsdy@hadron.UUCP (Joseph S. D. Yao) (09/27/86)
In article <111@titan.UUCP> eectrsef@titan.UUCP (Sean Eric Fagan - SA User Serv.) writes: >In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: >> /* a = b + b + b */ >> a = ((b=1),b) + ((b=2),b) + ((b=3),b) >>I expected the result to be 6. With the Microsoft C compiler and the >>compiler on the Sun 3, the result is 9. plus other comments tsk-tsk'ing this, etc. X3J11 states that subexpressions may be evaluated in any [presumably valid-jsdy] order, even if they produce side effects. The order in which side effects take place is unspecified. Side effects only have to be complete at what X3J11 calls "sequence points." The comma operator i s (in my [old] version) a sequence point, and the standard seems to require that at each comma, the left operand be evaluated and then the right, and the result be the latter. The example bears this out; but it is not as complicated as the above. Addition is not called a sequence point. HOWEVER As has been said before, X3J11 has little or nothing to do with contemporary C compilers. It hasn't even been issued yet! Not in final form. (So if the salesman knocks on your door with an "ANSI C compiler," slam it!) The bible has been K&R, which says specifically in the sections on Precedence and Order of Evaluation (K&R 2.12, Ref. 7.) the first two sentences above, plus: "When side effects (...) takes [sic] place is left to the discretion of the compiler, ... "... writing code which depends on order of evaluation is a bad programming practice in any language." Guy & Steele, although slightly influenced by X3J11, echo: (7.11) "It is, of course, bad programming style to have two side effects on the same variable in the same expression, because the order of the side effects is not defined; but the all-too-clever programmer here has reasoned that the order of the side effects doesn't matter, ..." It looks like your C compiler decided to evaluate all the lefts of the commas first, then the rights. For what it's worth, this resembles what G&S call "interleaving", which they deprecate in the evaluation of function arguments. (But not explicitly in this case.) Also for what it's worth, I would have hoped that the compiler did what you thought. HOWEVER (again), I've learned that where the document doesn't explicitly specify some part of the language, the definition of the language (for all practical purposes) resides in the compiler. -- Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP} jsdy@hadron.COM (not yet domainised)
jason@hpcnoe.UUCP (Jason Zions) (09/28/86)
Dale Worley (drw@cullvax.UUCP) writes:
Harbison&Steele (7.11) makes it clear that an implementation must
evaluate one argument of a binary operator completely before starting
evaluation of the other argument. Thus, the result should be 6. I
don't know what the ANSI standard says.
Unfortunately, he didn't read far enough into section 7.11, or he would have
seen the following passage:
The original description of C specified that subexpressions may be
evaluated in any order ... The matter of interleaving was not
discussed... We advise implementors to adhere rigidly to the
restrictions outlined here...
In this passage, H&S state very clearly that the restriction on interleaving
is one they have added, and that the restriction did not exist in prior
implementations.
In short, a C compiler implemented under K&R rules does indeed permit side-
effect evaluation in any order. Pure PCC-based compilers belong in this class.
I personally agree with H&S; it's an ugly thing to do. Of course, H&S also
say:
We also advise programmers not to exploit these restrictions too
heavily...
which I would contend the original example does. As I have said before, people
who use more than one side-effect on the same variable in a single statement
deserve everything they get.
Could one of the true C wizards (I'm still in training, sort of...) come up
with a general statement of "things to avoid doing" to keep from getting
bitten by this interleaving bug? The statement I make in the previous para-
graph is a first cut, but I recognize that it is both too restrictive and
insufficiently restrictive to avoid the problem.
--
Jason Zions Hewlett-Packard
Colorado Networks Division 3404 E. Harmony Road
Mail Stop 102 Ft. Collins, CO 80525
{ihnp4,seismo,hplabs,gatech}!hpfcdc!hpcnoe!jason
barada@maggot.applicon.UUCP (09/28/86)
/* Written 4:08 pm Sep 24, 1986 by cullvax.UUCP!drw in maggot:net.lang.c */ > In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: > > /* a = b + b + b */ > > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > > > >I expected the result to be 6. With the Microsoft C compiler and the > >compiler on the Sun 3, the result is 9. Apparently the parenthetical > >assignments are all getting done before the comma and addition. Any > >thoughts on this? Harbison&Steele (7.11) makes it clear that an implementation must evaluate one argument of a binary operator completely before starting evaluation of the other argument. Thus, the result should be 6. I don't know what the ANSI standard says. Dec VAX Ultrix gives 9. Lattice C 3.00 for MS-DOS gives 7!!! (Yes, that's "7", not a typo!) Dale /* End of text from maggot:net.lang.c */ I rearraged the above to a = (b,(b=1)) + (b,(b=2)) + (b,(b=3)); And my BSD4.2 VAX produced: movl $1,_b movl _b,r0 movl $2,_b movl _b,r1 addl2 r1,r0 movl $3,_b movl _b,r1 addl2 r1,r0 movl r0,_a As you can see, the comma operator is evaluated right to left. I think that this is a serious bug. BTW, this code produces the proper answer of 6. -- Peter Barada | (617)-671-9905 Applicon, Inc. A division of Schlumberger Ltd. | Billerica MA, 01821 UUCP: {allegra|decvax|mit-eddie|utzoo}!linus!raybed2!applicon!barada {amd|bbncca|cbosgd|wjh12|ihnp4|yale}!ima!applicon!barada Sanity is yet another perversion of reality.
KLH@SRI-NIC.ARPA (Ken Harrenstien) (09/29/86)
Someone asked what other compilers produced for the expression: a = ((b=1),b) + ((b=2),b) + ((b=3),b); I just tried it on KCC, the PDP-10 C compiler that I and others have developed (not a commercial product, but available). It returns 6. Of course, if it didn't I would have fixed it! As a general observation on questions of this nature, I would expect that compilers written since the publication of H&S have been much better (cleaner, more consistent, more predictable, etc) than their predecessors, because H&S is a much, MUCH better guide than K&R. Unfortunately for future implementors, the ANSI draft is more like K&R than H&S... -------
bet@ecsvax.UUCP (Bennett E. Todd III) (09/29/86)
In article <353@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes: >> In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: >> > /* a = b + b + b */ >> > a = ((b=1),b) + ((b=2),b) + ((b=3),b) >> > >> >I expected the result to be 6. With the Microsoft C compiler and the >> >compiler on the Sun 3, the result is 9. > >Dec VAX Ultrix gives 9. > >Lattice C 3.00 for MS-DOS gives 7!!! (Yes, that's "7", not a typo!) Microsoft C 3.0 small memory model gives 6 and DeSmet C 2.51 small memory model gives 7. Looks like this falls in the "don't count on the order of evaluation of subexpressions with side-effects" bucket, even though it doesn't look illegal. Certainly, anything that produces widely different answers under different popular implementations of C should be avoided; it is all well and good to try to say "such and so is RIGHT, and anything that does different is wrong" but that doesn't help portability. -Bennett -- Bennett Todd -- Duke Computation Center, Durham, NC 27706-7756; (919) 684-3695 UUCP: ...{decvax,seismo,philabs,ihnp4,akgua}!mcnc!ecsvax!duccpc!bet
fgd3@jc3b21.UUCP (Fabbian G. Dufoe) (09/29/86)
In article <111@titan.UUCP>, eectrsef@titan.UUCP writes: > In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: > > /* a = b + b + b */ > > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > > > >I expected the result to be 6. With the Microsoft C compiler and the > >compiler on the Sun 3, the result is 9. Apparently the parenthetical > >assignments are all getting done before the comma and addition. Any > >thoughts on this? > > > Tom, I agree, the result should be 6, as defined by K&R, but I have tried > it on a Cyber 180/830 running NOS VE, and get 9, also AT&T's 3B5 > System V, gets 9. > I would like everyone to test it on as many machines as prossible, to > see if we can find as least ONE other besides Small-C, that works. > > Mike Stump ucbvax!hplabs!csun!csunb!beusemrs I compiled the following code on an AT&T 3B2 (System V) and an Amiga (Lattice 3.03): main() { int a, b; a = ((b=1),b) + ((b=2),b) + ((b=3),b); printf("%d\n", a); a = (b=1) + (b=2) + (b=3); printf("%d\n", a); a = (b=1), a += (b=2), a += (b=3); printf("%d\n", a); } On the 3B2 it produced: 9 9 6 On the Amiga, surprisingly, it produced: 7 7 6 Both are wrong, but one can see where the 3B2 went wrong. How in the world did Lattice come up with 7? Fabbian Dufoe 350 Ling-A-Mor Terrace South St. Petersburg, Florida 33705 813-823-2350 UUCP: ...akgua!akguc!codas!peora!ucf-cs!usfvax2!jc3b21!fgd3
jsdy@hadron.UUCP (Joseph S. D. Yao) (09/29/86)
Oops, minor citation correction. Guy HARRIS reminds me: In article <580@hadron.UUCP> jsdy@hadron.UUCP (Joseph S. D. Yao) writes: >Guy & Steele, although slightly influenced by X3J11, echo: should be: >Harbison & Steele, although slightly influenced by X3J11, echo: Maybe one of these days I'll get married & stop posting after midnight ... being too busy with more important things ... -- Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP} jsdy@hadron.COM (not yet domainised)
throopw@dg_rtp.UUCP (Wayne Throop) (09/30/86)
> drw@cullvax.UUCP (Dale Worley) >> tomc@oakhill.UUCP (Tom Cunningham) >> /* a = b + b + b */ >> a = ((b=1),b) + ((b=2),b) + ((b=3),b) >> >> I expected the result to be 6. > Harbison&Steele (7.11) makes it clear that an implementation must > evaluate one argument of a binary operator completely before starting > evaluation of the other argument. Thus, the result should be 6. True. But note what H&S say at the end of section 7.11: The matter of interleaving was not discussed [in the original description of C...] We advise implementors to adhere [to the non-interleaving rule.] We also advise programmers not to exploit [this rule] too cleverly. And, as we have seen, their second bit of advice was well taken, since their first bit of advice seems to have been ignored in almost all implementations. > I don't know what the ANSI standard says. And the clincher is that ANSI didn't go along with H&S on this point. They say that expressions separated by "sequence points" may not be interleaved. These sequence points occur between "full expressions". Full expressions are initializers, expression statements, expressions in "if", "while" and the like, and expressions in "return". (I suspect that (?:) and (,) expressions have sequence points also, but couldn't find this on a trivial inspection of the draft standard.) Thus, ANSI C says that 9 is as good as 6, and repudiates H&S. So it goes. -- Sometimes I think the only universal in the computing field is the fetch-execute cycle. --- Alan J. Perlis -- Wayne Throop <the-known-world>!mcnc!rti-sel!dg_rtp!throopw
mdapoz@watrose.UUCP (Mark Dapoz) (09/30/86)
In article <4230@brl-smoke.ARPA> KLH@SRI-NIC.ARPA (Ken Harrenstien) writes: >Someone asked what other compilers produced for the expression: > a = ((b=1),b) + ((b=2),b) + ((b=3),b); I just tried this on my CP/M system using BDS C 1.5 and it gave me a value of 6. Mark Dapoz mdapoz@watrose.UUCP
pedz@bobkat.UUCP (Pedz Thing) (09/30/86)
In article <673@galbp.UUCP> gbm@galbp.UUCP (Gary McKenney) writes: >> In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: >> > /* a = b + b + b */ >> > a = ((b=1),b) + ((b=2),b) + ((b=3),b) >> > Lets change the expression from a = ((b=1),b) + ((b=2),b) + ((b=3),b) to a = ((a1),r1) + ((a2),r2) + ((a3),r3) Where a1 stands for assignment (to b) 1 and r1 stands for reference (to b) 1. The following conditions must be meet for proper code: a1 before r1 a2 before r2 a3 before r3 That is all of the restrictions imposed by C. Thus the following is correct code: a3, a2, a1, r1, r2, r3 which produces the answer of 3. I think I can come up with correct code which produces an answer anywhere form 3 to 9. This same question comes up every few days it seems like. I do not see what is so confusing about it. The simple law that C imposes no restrictions on the ordering of most operators never seems to be understood. Perry -- Perry Smith ctvax ---\ megamax --- bobkat!pedz pollux---/
blarson@usc-oberon.UUCP (Bob Larson) (10/01/86)
In article <8161@watrose.UUCP> mdapoz@watrose.UUCP (Mark Dapoz) writes: >In article <4230@brl-smoke.ARPA> KLH@SRI-NIC.ARPA (Ken Harrenstien) writes: >>Someone asked what other compilers produced for the expression: >> a = ((b=1),b) + ((b=2),b) + ((b=3),b); Microware C 2.0 for os9/68k has correct answers for both int and register int declarations of a and b. In other words, a is between 6 and 9 inclusive and b is between 1 and 3 inclusive. (If anyone is curious, a happens to be 6 and b happens to be 3, but I don't see how this matters.) -- Bob Larson Arpa: Blarson@Usc-Eclb.Arpa or blarson@usc-oberon.arpa Uucp: (ihnp4,hplabs,tektronix)!sdcrdcf!usc-oberon!blarson
fgd3@jc3b21.UUCP (Fabbian G. Dufoe) (10/03/86)
Earlier this week I posted the following (Message-ID: <468@jc3b21.UUCP>): > I compiled the following code on an AT&T 3B2 (System V) and an > Amiga (Lattice 3.03): > > main() > { > int a, b; > a = ((b=1),b) + ((b=2),b) + ((b=3),b); > printf("%d\n", a); > a = (b=1) + (b=2) + (b=3); > printf("%d\n", a); > a = (b=1), a += (b=2), a += (b=3); > printf("%d\n", a); > } > > On the 3B2 it produced: > > 9 > 9 > 6 This evening I received the following mail: > While I disagree about the "required" result for the first expression, > I have no doubt that 6 and 6 are required for the second two, and I > believe that our 3B2 compilers give those results. The value of an > assignment or assignment-op is always the value of its left side. > I would appreciate it if you would double-check your result and post > a correction on the net. > > Dave Kristol > AT&T > ...akgua!acguc!codas!sfbc!dmk OK, Dave. I compiled and ran the program again on the 3B2. It produced 9, 9, and 6, just as I said the first time. Now let me take issue with the errors in your note. (1) There is no significant difference between the first two expressions. Whatever reason you have to disagree about the required result for the first should apply to the second as well. Thus ((b=1),b) doesn't do anything in this case which (b=1) doesn't do. (2) I reviewed K&R for some light on what result the first and second expressions should produce. I found the following sentence on page 49: "As mentioned before, expressions involving one of the associative and commutative operators (*, +, &, ^, |) can be rearranged even when parenthesized." And people call BASIC brain-damaged! This means the results of the first two expressions are unpredictable without knowledge of the specific C compiler involved. Furthermore, it implies the following expression is unpredictable: a = (((b=1) + (b=2)) + (b=3)) Incredible as it may seem, the 3B2 thinks "a" will be 9. (The Amiga, with Lattice, thinks "a" will be 7.) I believe that is a serious flaw in the language definition. Two C compilers, both correctly following the definition in K&R, can compile the same legal C expression and come up with different results. Oh, well. Who said C was a portable language? (3) You said you believe the 3B2 produces the results you thought correct. Why didn't you check? Your reasoning seemed to be "I think the correct results are 9, 6, and 6. I think the 3B2 compiler is always right. Therefore the results must have been 9, 6, and 6." To my thinking, the proper response would have been "Maybe there is something wrong here. I'll compile the program and see the results for myself. Hmm...The results are 9, 9, and 6. I wonder what's wrong with the compiler or my understanding of C?" Do you see the difference? This has certainly been an instructive exercise for me. It is important to understand peculiarities like that. If I hadn't gone into it this carefully I'd have been bitten later on when the result was critical. Thanks for making me take such a hard look at the question. Fabbian Dufoe 350 Ling-A-Mor Terrace South St. Petersburg, Florida 33705 813-823-2350 UUCP: ...akgua!akguc!codas!peora!ucf-cs!usfvax2!jc3b21!fgd3
gof@NOSC.ARPA (10/03/86)
> a = ((b=1),b) + ((b=2),b) + ((b=3),b);
Someone posted that Microsoft C gives 9. I think they were refering to pre v.3
(which was identical to Lattice) as Version 3.0 gives 6.
Jerry Fountain
crash!pnet01!gof@nosc
garys@bunker.UUCP (Gary M. Samuelson) (10/03/86)
Instead of a = ((b=1),b) + ((b=2),b) + ((b=3),b); I would like to suggest using a = ((b=1),b) + ((b=4),b) + ((b=16),b); This has the advantage that the result in a is unambiguous. For example, the answer '7' could be 1+3+3 or 2+2+3, but with the modified test case, the same order of evaluation would produce 33 or 24. Furthermore, the (supposedly) correct answer '6' could be incorrectly generated by 2+2+2, instead of 1+2+3. The modified test will produce 12 or 21, respectively. Gary Samuelson
markp@valid.UUCP (Mark P.) (10/05/86)
> In article <673@galbp.UUCP> gbm@galbp.UUCP (Gary McKenney) writes: > >> In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: > >> > /* a = b + b + b */ > >> > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > >> > > > Lets change the expression from > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > to > a = ((a1),r1) + ((a2),r2) + ((a3),r3) > > Where a1 stands for assignment (to b) 1 and r1 stands for reference > (to b) 1. The following conditions must be meet for proper code: > a1 before r1 > a2 before r2 > a3 before r3 > > That is all of the restrictions imposed by C. Thus the following is > correct code: > > a3, a2, a1, r1, r2, r3 > > which produces the answer of 3. I think I can come up with correct > code which produces an answer anywhere form 3 to 9. > > This same question comes up every few days it seems like. I do not > see what is so confusing about it. The simple law that C imposes no > restrictions on the ordering of most operators never seems to be > understood. > > Perry Finally a sensical response. In other words, instead of all crying of how all the compilers do different things under ambiguous K&R guidelines, just DON'T WRITE THIS TYPE OF CODE. Face it, since there are compilers in existence that don't generate code for expressions in exactly the same order, then engaging in this "creative" programming is NON-PORTABLE. Expression rearrangement is an extremely valuable tool in optimization. For instance, consider the following simple example: a= (b+c)+d Assume that b is a memory variable, but that a and c and d are registers, and furthermore that the processor has a delayed load (not an unreasonable situation for a RISC). The generated code would then look like: load rb, _b add ra, rc, rd ; load completes during this instruction add ra, ra, rb Here we see the value of breaking the user's parentheses in associative/ commutative operator evaluation in order to save one instruction. In another type of machine with multiple functional units, the possibilities for expression optimization are endless. I would not want to castrate the potential of such machines just so some people could write "clever-looking" code that is explicitly warned against in the ANSI standard. And please stop complaining about a situation that won't, can't, and shouldn't go away. Mark Papamarcos Valid Logic Systems hplabs!ridge!valid!markp
robison@uiucdcsb.cs.uiuc.edu (10/05/86)
> (2) I reviewed K&R for some light on what result the first and second > expressions should produce. I found the following sentence on page 49: > "As mentioned before, expressions involving one of the associative and > commutative operators (*, +, &, ^, |) can be rearranged even when > parenthesized." And people call BASIC brain-damaged! This means > the results of the first two expressions are unpredictable without > knowledge of the specific C compiler involved.... > ...I believe that is a serious flaw in the > language definition. Two C compilers, both correctly following the > definition in K&R, can compile the same legal C expression and come up > with different results. Oh, well. Who said C was a portable language? > 1. It is not a flaw in a language to specify certain constructs as undefined. If the C compilers were not allowd to re-arrange expressions, then the results could be exactly defined, at the cost of slowing the program down. On page 50, K&R points out that "the best order strongly depends on machine architecture". C was designed for writing efficient programs on a variety of machines. 2. The operations *,+,&,^,| are commutative and associative in mathematics. To write code depending on a particular evaluation order is a very poor practice. The meaning of the code may be obvious to you, but other readers will most likely be mislead. Programmers should strive for clarity of expression. 3. Determinism is not always a good thing, for example it can slow down parallel processors. Some languages (e.g. Dijkstra's guarded commands) may not give you the same result on the same machine. 4. Programs are portable if written properly, i.e. pay heed to K&R's warnings. I use to port and maintain programs for a large computer company. The company has a "portable" language which supposedly runs identically on all its various processors. Therefore the programmers should never have to worry about machine-dependencies. Those programs were difficult to port, because the language did NOT run identically on all processors, and the programmers never bothered to think about the implications. 5. In contrast to (3), I have written a large program in C which runs on VAX's, PCs, and the CRAY. The port to the PC/RT took 13 minutes, because I took time when writing to avoid portability problems. In short, C's undefined constructs are not a flaw and do not deter writing portable code. Arch D. Robison robison@uiucdcs University of Illinois at Urbana-Champaign
Wilkinson@HI-MULTICS.ARPA (10/06/86)
On an Intel 286/310 running Xenix 3 updt 3 I get: a= ((b=1),b)+((b=2),b)+((b=3),b); RESULT a = 9 a= (b,(b=1))+(b,(b=2))+(b,(b=3)); RESULT a = 6 Richard Wilkinson (Wilkinson@HI-MULTICS)
len@geac.UUCP (Leonard Vanek) (10/07/86)
The one thing that is clear from all of the discussion on the problem of expression sequencing is that one can never be sure of the order in which an expression in C will be evaluated. Although that I agree that it is asking for trouble to mix side effects in with complicated expressions, I still believe that it is a pity that C (even Ansi C) does not even let the programmer tell it what order is desired by the use of parentheses! To ignore parentheses in determining the evaluation order (i.e. (a+b)+c does not guarantee that a and b are added first) causes problems with round off errors, not just side effects -- and is totally counter-intuitive. --------------------------------------------------------------------- Leonard Vanek phone (416) 475-0525 Geac Computers International 350 Steelcase Rd. West USENET ... !utzoo!yetti!geac!len Markham Ontario L3R 1B3 Canada Note: My Usenet path is subject to change on short notice!
chris@umcp-cs.UUCP (Chris Torek) (10/09/86)
In article <160@geac.UUCP> len@geac.UUCP (Leonard Vanek) writes: >... I agree that it is asking for trouble to mix >side effects in with complicated expressions, [but] I still believe >that it is a pity that C (even Ansi C) does not even let the >programmer tell it what order is desired by the use of parentheses! >To ignore parentheses in determining the evaluation order (i.e. >(a+b)+c does not guarantee that a and b are added first) causes >problems with round off errors, not just side effects -- and is >totally counter-intuitive. If you want `a+b' to be done first, then `result + c', use result = a + b; result += c; The solution is trivial, and the `problem' is well documented. To those to whom parentheses directly determine order of evaluation, I suppose this is indeed troublesome. As for myself, I never expect parentheses to do more than override default precedence, so it is not `totally counter-intuitive' to me. Even in Fortran I (where, I believe, the language specification says that (A+B)+C is requires doing A+B first, then result+C) I would write RESULT = A + B RESULT = RESULT + C ---if that were what I meant. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
chris@umcp-cs.UUCP (Chris Torek) (10/09/86)
Incidentally, I once used a system in which parentheses determined only precedence. (I used it early in my programming ventures, which may explain my mindset.) It did something rather novel, which might help all these C programmers who think parentheses directly control evaluation order: It removed any `unnecessary' parentheses. (The system, incidentally, was an HP 9825A `desk-top calculator', as part of an HP 3060A board test system.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
coltoff@burdvax.UUCP (Joel Coltoff) (10/09/86)
In article <160@geac.UUCP>, len@geac.UUCP (Leonard Vanek) writes: > The one thing that is clear from all of the discussion on > the problem of expression sequencing is that one can never > be sure of the order in which an expression in C will be > evaluated. Not always true. Logical expressions are evaluated left to right. > I still believe that it is a pity that C (even Ansi C) does not even > let the programmer tell it what order is desired by the use > of parentheses! To ignore parentheses in determining the > evaluation order (i.e. (a+b)+c does not guarantee that a and > b are added first) causes problems with round off errors, > not just side effects -- and is totally counter-intuitive. Agreed. But keep this in mind. C can change the order in which it evaluates expressions, we told you that when you took this job, what it doesn't do is change the order in which it evalutes statements. If you really want to do (a+b) + c then do it like this x = a + b; x += c; Yes it uses more variables, generates more code and is less efficient but it gets the correct answer. This is often much more important than any of the other considerations we make when we write programs. Now to throw in my few shekels. When you do something like a = (b=1,b) + (b=2,b) + (b=3,b); or more realistically if ( a < b || ( c = ( x/y ) ) == 42 || d == data[i] ) you deserve to get burned. Sure the langauge lets you do things like assign a value to c and compare it to 42 in the same expression but keep in mind that that assignment isn't done on each pass through that block of code.
henry@utzoo.UUCP (Henry Spencer) (10/09/86)
> ... I still believe that it is a pity that C (even Ansi C) does not even > let the programmer tell it what order is desired by the use > of parentheses! ... The problem, as has been mentioned before, is that parentheses are also used to override the precedence rules for operators. This is a use in which one does *not* necessarily want to imply the forcing of evaluation order. There really is no entirely satisfactory solution except to use two different constructs for the two different roles. C opted long ago to use parentheses for precedence overrides, and to require explicit assignment to a temporary to force order of evaluation. X3J11 has actually added a few hooks for order control, but changing the meaning of parentheses for that purpose wasn't considered wise. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,decvax,pyramid}!utzoo!henry
tps@sdchem.UUCP (Tom Stockfisch) (10/10/86)
In article <160@geac.UUCP> len@geac.UUCP (Leonard Vanek) writes: >The one thing that is clear from all of the discussion on >the problem of expression sequencing is that one can never >be sure of the order in which an expression in C will be >evaluated. > >... >... To ignore parentheses in determining the >evaluation order (i.e. (a+b)+c does not guarantee that a and >b are added first) causes problems with round off errors, >not just side effects -- and is totally counter-intuitive. Allowing optimizing compilers the freedom to rearrange expressions is (I am told) crucial to performance on many machines. Good portability means not only that a program will w o r k on any machine, but that it will work e f f i c i e n t l y on any machine, and people won't be tempted to waste time fine-tuning programs to many different machines (a maintenance nightmare). For non-numerical calculations, order of evaluation almost never matters, except with poorly written expressions (e.g. multiple side effects). For numerical calculations it would be very nice to be able to specify order. Breaking up the expression into individual ones is n o t a viable option, as serious numerical work can have rather long expressions which would be rendered unreadable. I think the best solution would be a unary operator with syntax like 'return', so that the compiler would have to respect parentheses for order of evaluation of the following statement. Unfortunately, this would probably mean another key word or another obscure overloading of a current one. But a feature like this is really important for numerical programming. For instance, call the operator "respect". Then respect <expr> ; would mean that <expr> must have its parentheses respected. I think this is much better than respect( <expr> ); because extra parentheses tend to muck things up in numeric work, altho of course wimps (:-) who insist on using return(expr); instead of return expr; could do likewise with "respect". -- -- Tom Stockfisch, UCSD Chemistry
Schauble@MIT-MULTICS.ARPA (Paul Schauble) (10/10/86)
OK, so (b=1,b)+(b=2,b) is ambiguous. Now, is it reasonable to ask lint to flag things like this?? Paul Schauble at MIT-Multics
peters@cubsvax.UUCP (Peter S. Shenkin) (10/10/86)
In article <umcp-cs.3769> chris@umcp-cs.UUCP (Chris Torek) writes: > >If you want `a+b' to be done first, then `result + c', use > > result = a + b; > result += c; > >The solution is trivial, and the `problem' is well documented. > ...I never expect >parentheses to do more than override default precedence, so it is >not `totally counter-intuitive' to me. One of the attractions of C is its elegance and conciseness of expression; having to declare a variable only for the purpose of defining order of evaluation, even when the expression is extremely simple, is inelegant and inconcise, and the requirement to do so can easily double the size (as measured by the number of lines) of source code in numerical work where rounding error is significant and such order has to be thoroughly thought through. C wasn't originally designed for such applications, of course, but now that we're going to be able to do single-precision arithmetic across function calls there's going to be less and less reason to avoid using C; unfortunately, this parentheses thing is going to remain one of them. I understand the reason for the accepted convention, and I accept that reason, but even if it's necessary it's a necessary evil; let's not make a virtue out of it. I wish there were some way of forcing order of execution, to this extent anyway, within a line. Peter S. Shenkin Columbia Univ. Biology Dept., NY, NY 10027 {philabs,rna}!cubsvax!peters cubsvax!peters@columbia.ARPA
henry@utzoo.UUCP (Henry Spencer) (10/10/86)
> For numerical calculations it would be very nice to be able > to specify order. Breaking up the expression into individual ones is n o t > a viable option... I think the best solution would be a unary operator > with syntax like 'return', so that the compiler would have to respect > parentheses for order of evaluation of the following statement... > > respect <expr> ; X3J11 has not done quite this, but they have provided a way to specify a "fence" within an expression. The unary plus operator, originally provided for relatively minor reasons of consistency, also does this job. To force the parenthesized addition in "(a+b)+c" to be done first, write "+(a+b)+c". (Unary operators have higher priority than binary, so "+(a+b)" is an operand of the last "+".) The official definition of the effect is something like "inhibits regrouping of subexpressions within its operand with subexpressions outside it". I can't say that I am in love with the syntax, but the facility is there. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,decvax,pyramid}!utzoo!henry
chris@umcp-cs.UUCP (Chris Torek) (10/11/86)
In article <4504@brl-smoke.ARPA> Schauble@MIT-MULTICS.ARPA (Paul Schauble) writes: >OK, so (b=1,b)+(b=2,b) is ambiguous. Now, is it reasonable to ask lint >to flag things like this?? Yes. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
simon@its63b.ed.ac.uk (ECSC68 S Brown CS) (10/11/86)
In article <2076@ecsvax.UUCP> bet@ecsvax.UUCP (Bennett E. Todd III) writes: >In article <353@cullvax.UUCP> drw@cullvax.UUCP (Dale Worley) writes: >>> In article <760@oakhill.UUCP> tomc@oakhill.UUCP (Tom Cunningham) writes: >>> > /* a = b + b + b */ >>> > a = ((b=1),b) + ((b=2),b) + ((b=3),b) >>> > >>> >I expected the result to be 6. With the Microsoft C compiler and the >>> >compiler on the Sun 3, the result is 9. >>Dec VAX Ultrix gives 9. >>Lattice C 3.00 for MS-DOS gives 7!!! (Yes, that's "7", not a typo!) >Microsoft C 3.0 small memory model gives 6 and DeSmet C 2.51 small >memory model gives 7. > >Looks like this falls in the "don't count on the order of evaluation of >subexpressions with side-effects" bucket, even though it doesn't look >illegal. > >Certainly, anything that produces widely different answers under >different popular implementations of C should be avoided; it is all well >and good to try to say "such and so is RIGHT, and anything that does >different is wrong" but that doesn't help portability. > Ok, this seems good advice for expressions where each subexression _must_ be evaluated at _some_ time. But, how about c = (b=1,a==1) || (b=2,a==0) || (b=3,a==3) || (b=4,a==2); as a quick nice way of saying switch (a) { case 1: b=1; c=1; break; case 0: b=2; c=1; break; case 3: b=3; c=1; break; case 2: b=4; c=1; break; default: c=0; } where the evaluation will "break off" at the point where one of the comparisons first succeeds. (I actually wanted to use something a bit like this a few days ago, but now I'm not too sure its that portable at all, considering all the problems with "+"). Of course, compilers on which _this_ doesn't work should be considered even *more* wrong than those as described above, but that's not too constructive a complaint... -- Simon Brown Dept. of Computer Science, University of Edinburgh. {seismo,ihnp4,decvax}!mcvax!ukc!cstvax(!its63b?)!simon
levy@ttrdc.UUCP (Daniel R. Levy) (10/15/86)
In article <559@cubsvax.UUCP>, peters@cubsvax.UUCP (Peter S. Shenkin) writes: >>If you want `a+b' to be done first, then `result + c', use >> >> result = a + b; >> result += c; >> >>The solution is trivial, and the `problem' is well documented. >> ...I never expect >>parentheses to do more than override default precedence, so it is >>not `totally counter-intuitive' to me. >One of the attractions of C is its elegance and conciseness of expression; >having to declare a variable only for the purpose of defining order of >evaluation, even when the expression is extremely simple, is inelegant and >inconcise, and the requirement to do so can easily double the size (as measured >by the number of lines) of source code in numerical work where rounding error >is significant and such order has to be thoroughly thought through. > >C wasn't originally designed for such applications, of course, but now that >we're going to be able to do single-precision arithmetic across function >calls there's going to be less and less reason to avoid using C; unfortunately, >this parentheses thing is going to remain one of them. >I understand the reason for the accepted convention, and I accept that reason, >but even if it's necessary it's a necessary evil; let's not make a virtue >out of it. I wish there were some way of forcing order of execution, to >this extent anyway, within a line. >Peter S. Shenkin Columbia Univ. Biology Dept., NY, NY 10027 In C, you can put more than one statement on a line! So it would be feasible, if awkward, to do something like float a,b,c,d,e,t; t=a+b;t+=c;d*=t;d/=e; for the FORTRAN D=(D*((A+B)+C))/E Obviously it's possible but unnecessary to use four different lines: t=a+b; t+=c; d*=t; d/=e; -- ------------------------------- Disclaimer: The views contained herein are | dan levy | yvel nad | my own and are not at all those of my em- | an engihacker @ | ployer or the administrator of any computer | at&t computer systems division | upon which I may hack. | skokie, illinois | -------------------------------- Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa, go for it! allegra,ulysses,vax135}!ttrdc!levy
fgd3@jc3b21.UUCP (10/15/86)
In article <139200039@uiucdcsb>, robison@uiucdcsb.cs.uiuc.edu writes: > > > the results of the first two expressions are unpredictable without > > knowledge of the specific C compiler involved.... > > ...I believe that is a serious flaw in the > > language definition. Two C compilers, both correctly following the > > definition in K&R, can compile the same legal C expression and come up > > with different results. Oh, well. Who said C was a portable language? > > 4. Programs are portable if written properly, i.e. pay heed to K&R's warnings. > I use to port and maintain programs for a large computer company. > The company has a "portable" language which supposedly runs identically > on all its various processors. Therefore the programmers should never > have to worry about machine-dependencies. Those programs were difficult > to port, because the language did NOT run identically on all > processors, and the programmers never bothered to think about the > implications. > > 5. In contrast to (3), I have written a large program in C which runs on > VAX's, PCs, and the CRAY. The port to the PC/RT took 13 minutes, because > I took time when writing to avoid portability problems. > > > Arch D. Robison robison@uiucdcs > University of Illinois at Urbana-Champaign Your examples support my point: a _portable_ language is one which runs identically on all implementations. A language which permits the code generated by its statements to be implementation-dependent is not portable. When dealing with a non-portable language (like C) you can work around the problem by avoiding those statements which are evaluated in an implementation-dependent way. But if portability is important to you--and I believe it should be--then it is a flaw in the language definition to permit the evaluation of statements which are syntactically correct to depend on the implementation. In (4) above you describe a language which was supposed to be portable but wasn't. Failing to work around the non-portable features caused problems. In (5) above you describe a C program which was portable specifically because you "took time when writing to avoid portability problems." Fabbian Dufoe 350 Ling-A-Mor Terrace South St. Petersburg, Florida 33705 813-823-2350 UUCP: ...akgua!akguc!codas!peora!ucf-cs!usfvax2!jc3b21!fgd3
chris@umcp-cs.UUCP (Chris Torek) (10/16/86)
In article <559@cubsvax.UUCP> peters@cubsvax.UUCP (Peter S. Shenkin) writes: >One of the attractions of C is its elegance and conciseness of >expression; having to declare a variable only for the purpose of >defining order of evaluation, even when the expression is extremely >simple, is inelegant and inconcise, .... I wrote a nice long reply to this, but it fell into the news rubbish heap because the `active' file was too long. Naturally the posting software did not bother to keep a copy of my text, since inews never fails. Right. Summary: if you think C needs something to force evaluation order, *implement something*. Test it well. If it works, *then* lobby for its adoption. If, for example, you think altering the meaning of parentheses will not be harmful, try it. If you prefer `order bracketing' such as `[a + b] + c', try that. But whatever you try, TEST IT WELL before you cast it in concrete (via X3J11 or whatnot).
00R0DHESI%bsu.csnet@CSNET-RELAY.ARPA (Rahul Dhesi) (10/16/86)
Peter S. Shenkin <cubsvax!peters@columbia.ARPA> writes: <In article <umcp-cs.3769> chris@umcp-cs.UUCP (Chris Torek) writes: << result = a + b; << result += c; <... <...I wish there were some way of forcing order of execution, to <this extent anyway, within a line. Try this: {int t = a + b; result = t + c;} /* note: force evaluation order */ This construct is general and it achieves the purpose. The extra variable exists only in the block and doesn't clutter up the rest of the program. And its very presence shouts "Careful!" to next person who modifies the code. C doesn't cry wolf. Other languages do. Rahul Dhesi <dhesi%bsu@csnet-relay.ARPA> !seismo!csnet-relay.ARPA!bsu!dhesi Yes, I know they go the wrong way.
greg@utcsri.UUCP (Gregory Smith) (10/17/86)
In article <483@jc3b21.UUCP> fgd3@jc3b21.UUCP writes: > Your examples support my point: a _portable_ language is one which >runs identically on all implementations. A language which permits the code >generated by its statements to be implementation-dependent is not portable. But if the statements produce the same result, despite being evaluated in a different order, then the *program* is portable. >When dealing with a non-portable language (like C) you can work around the >problem by avoiding those statements which are evaluated in an >implementation-dependent way. But if portability is important to you--and >I believe it should be--then it is a flaw in the language definition to >permit the evaluation of statements which are syntactically correct >depend on the implementation. The following is a syntactically correct statement 1 = 1.0(); which obviously is semantically incorrect. So insert '... and semantically ..' in the above assertion. Now one could argue that a[i]=i++; is semantically incorrect in 'portable' C, even though it takes lint to catch it. The programmer can determine whether a statement will be portable or not due to side-effects. If you make a compiler which does not fiddle with the order of evaluation, then you may be making *all* statements portable, but your compiler will generate significantly less efficient code for a lot of statements which were already portable. The main point is that the bounds of portability are well defined, ( at least they will be with ANSI C), so all you have to do is avoid the non-portable stuff. Why would anybody write x[i]=i++; or func( --i,--i) or j = i+i++; etc? Even if you know it will not ported and are clever enough to know what it does on your current compiler, it is not obvious to someone reading the code. In fact the reader will have to look at the assembler produced, or write a test program. If you fix this by forcing order of evaluation, we will just have a whole new set of rules to remember. C operator hierarchy is already enough :-) From: mwm@eris.berkeley.edu (Mike Meyer) > Euclid: Maybe portable, but is there more than one implementation? We have coders for PDP-11, 68000, vax, 6809, NS16K and possibly a few more. You can still get burned by different word sizes, but there are tools which can and should be used if you want portability. Sorry if this is a little muddled, but current system load makes editing a very time-consuming chore. -- ---------------------------------------------------------------------- Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg
dik@mcvax.uucp@ndmce.uucp (Dik T. Winter) (10/17/86)
In article <3769@umcp-cs.UUCP> chris@umcp-cs.UUCP (Chris Torek) writes: > Even in Fortran I (where, >I believe, the language specification says that (A+B)+C is requires >doing A+B first, then result+C) I would write > > RESULT = A + B > RESULT = RESULT + C > And so should it. Once I required the expression (A - B) - C evaluated exactly that way. It didn't do so. However, after removing the parenthesis it was evaluated the way I wanted. Counterintuitive? -- dik t. winter, cwi, amsterdam, nederland UUCP: {seismo,decvax,philabs,okstate,garfield}!mcvax!dik or: dik@mcvax.uucp ARPA: dik%mcvax.uucp@seismo.css.gov
faustus@ucbcad.BERKELEY.EDU@ndmce.uucp (Wayne A. Christopher) (10/18/86)
In article <483@jc3b21.UUCP>, fgd3@jc3b21.UUCP writes: > Your examples support my point: a _portable_ language is one which > runs identically on all implementations. A language which permits the code > generated by its statements to be implementation-dependent is not portable. A language can't be called portable, but programs written in that language can. A measure of how useful a language is how easy it is to write portable code in it. By your definition, you could call any language "non-portable" because you can always (at least if the language is used for real things) write code that determines what kind of processor it is running on. > When dealing with a non-portable language (like C) ... I know of no other (useful) language which is as easy to write portable code in as C. Most other common languages such as lisp suffer from a lack of a standard such as K&R which all compilers follow (at least in theory). (I know, there is a lisp standard now...) > But if portability is important to you--and > I believe it should be--then it is a flaw in the language definition to > permit the evaluation of statements which are syntactically correct to > depend on the implementation. Most of these cases where things are implementation-dependent are situations where the hardware must dictate how things are to be done if they are to be done in an optimal manner. For instance, order of argument evaluation must depend on the implementation because different machines like different stack setups. Anyway, there is 'lint', so it should be very easy to write portable C code if you try. Wayne
dant@tekla.UUCP (10/18/86)
Simon Brown ( simon@its63b.ed.ac.uk (ECSC68 S Brown CS)) writes: >But, how about > c = (b=1,a==1) || (b=2,a==0) || (b=3,a==3) || (b=4,a==2); >as a quick nice way of saying > switch (a) { > case 1: b=1; c=1; break; > case 0: b=2; c=1; break; > case 3: b=3; c=1; break; > case 2: b=4; c=1; break; > default: c=0; > } >where the evaluation will "break off" at the point where one of >the comparisons first succeeds. > >(I actually wanted to use something a bit like this a few days ago, >but now I'm not too sure its that portable at all, considering >all the problems with "+"). These two statements are NOT identical. To make them the same the default case would need to be changed to: default: b=4; c=0; The switch is superior to the assignment for three reasons: 1) You probably don't want to change b in the default case. 2) Efficiency. In all but the first case the assignment statement will assign several values to b before reaching the true condition. 3) Maintainability. The switch makes it obvious what's happening The assignment has potential in the Obfuscated C Contest. Dan Tilque UUCP: tektronix!dadla!dant CSnet: dant%dadla@tektronix ARPAnet: dant%dadla%tektronix@csnet-relay "This is a bust!" she yelled, as she ripped open her coat, boldly displaying her ample authority. -- R. J. Wilcek From _Son_of_"It Was a Dark and Stormy Night"_
JOSH@ibm-sj.ARPA (Joshua W. Knight) (10/18/86)
There have been lots of lamentations about C not providing a way to force evaluation order. The original subject (with multiple "side effect" assignments to the same variable) isn't really the issue here. One legitimate concern is truncation and such in numerical calculations. The ANSI C draft standard provides the unary plus operator for coercing evaluation order. Thus a = +(b + c) + +(d) ; should force the sum of b+c to be calculated and added to d. This is probably less pleasing to the eye but, as has been pointed out before, parentheses already have a meaning in C, and it is explicitly NOT one that forces order of evaluation. Of course I speak only for myself, not my employer. Josh Knight IBM T.J. Watson Research Center josh@ibm.com, josh@yktvmh.BITNET
peters@cubsvax.UUCP (10/20/86)
In article <brl-smok.4642> 00R0DHESI%bsu.csnet@CSNET-RELAY.ARPA (Rahul Dhesi) writes: >Peter S. Shenkin <cubsvax!peters@columbia.ARPA> writes: ><In article <umcp-cs.3769> chris@umcp-cs.UUCP (Chris Torek) writes: ><< result = a + b; ><< result += c; ><... ><...I wish there were some way of forcing order of execution, to ><this extent anyway, within a line. > >Try this: > {int t = a + b; result = t + c;} /* note: force evaluation order */ So many have replied to me on this subject, both here and by netmail, that I'd like to point out publicly what someone reminded me of by mail. The draft ANSI standard specifies that unary "+" guarantees that a parenthesized expression following it will be evaluated without interleaving or other change of order; thus, using the example previously bandied about, the usage: a = +( (b=1), b ) + +( (b=4), b ) + +( (b=16), b ) will guarantee that a is given a value of 21. I rather like this; it allows the code writer to specify where he thinks order of evaluation is important, and allows the compiler to optimize the order where it's not. We now have the following comparison: Fortran: parentheses specify both precedence of operators and order of evaluation of operators with equal precedence, even when the operators are commutative; C: parentheses specify only precedence of operators. Commutative operators can have their arguments evaluated in any order, but the default order, which will be compiler-dependent, can be overridden with the unary "+". You guys are giving us numerical folks less and less excuse to keep using Fortran (break my heart).... 'Nuff said? Peter S. Shenkin Columbia Univ. Biology Dept., NY, NY 10027 {philabs,rna}!cubsvax!peters cubsvax!peters@columbia.ARPA
asw@tony.UUCP (Tony Williams) (10/20/86)
In article <11900001@maggot> barada@maggot.applicon.UUCP writes: >> > a = ((b=1),b) + ((b=2),b) + ((b=3),b) > >I rearraged the above to > > a = (b,(b=1)) + (b,(b=2)) + (b,(b=3)); this isn't a rearragement (sic), but a different statement. > >And my BSD4.2 VAX produced: > > movl $1,_b > movl _b,r0 > movl $2,_b > movl _b,r1 > addl2 r1,r0 > movl $3,_b > movl _b,r1 > addl2 r1,r0 > movl r0,_a > >As you can see, the comma operator is evaluated right to left. I think that No, it is not. >this is a serious bug. Ah yes, but the bug is in your code, not the compiler. > >BTW, this code produces the proper answer of 6. > There is no single proper answer. The comma operator is defined to evaluate the left operand, discard it, then evaluate the right operand, and return the resulting value, ie that of the RIGHT operand. So, (b,b=1) evaluates b and discards it, evaluates b=1, assigning one to b, and returns the result which is the new value of b. Your statement is therefore equivalent to a = (b=1) + (b=2) + (b=3); which is equiivalent to a = 1 + 2 + 3; followed or preceded by the assignements to b in ANY order. The compiler has elided the evaluations of b, as the result is to be discarded and there are no side-effects. In summary, the compiler *is* allowed to reorder operands of operators like +, but you are *not* allowed to reorder the operands of "," and expect the same result. --------------------------------------------------------------------------- Tony Williams |Informatics Division UK JANET: asw@uk.ac.rl.vd |Rutherford Appleton Lab Usenet: {... | mcvax}!ukc!rlvd!asw |Chilton, Didcot ARPAnet: asw%vd.rl.ac.uk@ucl-cs.arpa |Oxon OX11 0QX, UK
c@hpdsd.UUCP (C Compiler Project(Debbie Coutant)) (10/21/86)
/Just for the record, There is a new operator specified by the proposed ANSI :q! :q q hpdsd:net.lang.c / faustus@ucbcad.BERKELEY.EDU@ndmce.uucp (Wayne A. Christopher) / 2:09 pm Oct 17, 1986 / In article <483@jc3b21.UUCP>, fgd3@jc3b21.UUCP writes: > Your examples support my point: a _portable_ language is one which > runs identically on all implementations. A language which permits the code > generated by its statements to be implementation-dependent is not portable. A language can't be called portable, but programs written in that language can. A measure of how useful a language is how easy it is to write portable code in it. By your definition, you could call any language "non-portable" because you can always (at least if the language is used for real things) write code that determines what kind of processor it is running on. > When dealing with a non-portable language (like C) ... I know of no other (useful) language which is as easy to write portable code in as C. Most other common languages such as lisp suffer from a lack of a standard such as K&R which all compilers follow (at least in theory). (I know, there is a lisp standard now...) > But if portability is important to you--and > I believe it should be--then it is a flaw in the language definition to > permit the evaluation of statements which are syntactically correct to > depend on the implementation. Most of these cases where things are implementation-dependent are situations where the hardware must dictate how things are to be done if they are to be done in an optimal manner. For instance, order of argument evaluation must depend on the implementation because different machines like different stack setups. Anyway, there is 'lint', so it should be very easy to write portable C code if you try. Wayne ----------
c@hpdsd.UUCP (C Compiler Project(Debbie Coutant)) (10/21/86)
There is a new operator in the proposed ANSI C standard that forces expression grouping, it is the unary plus operator. The unary plus is only useful for expressions that involve >1 uses of the same operator, for example: a+b+c With the unary plus operator a+b+c can be forced to be evaluated as (a+b)+c using the following: +(a+b) + c By ANSI's definition this will force (a+b) to be evaluated first. Looks like somebody thought of the order-of-evaluation problem and attempted to 'fix' it in the ANSI proposal already.
rbutterworth@watmath.UUCP (Ray Butterworth) (10/21/86)
> The ANSI C draft standard provides the unary plus operator for coercing > evaluation order. Thus > a = +(b + c) + +(d) ; > should force the sum of b+c to be calculated and added to d. This is > probably less pleasing to the eye but, as has been pointed out before, > parentheses already have a meaning in C, and it is explicitly NOT one > that forces order of evaluation. Does X3J11 (or any other C "standard") say anything about the order of evaluation of (possibly redundant) cast expressions? e.g. ( ((double)(a+b)) + ((double)(c+d)) ) where a, b, c, and d may or may not be type (double)? It would certainly be prettier than the unary " +" operator, and certainly more obvious that the programmer really did want the given grouping.