fpb@ittc.wec.com (Frank P. Bresz) (06/05/91)
This is a post for a friend: Direct replies to fpb@ittc.wec.com because I am interested and perkins@cgi.com, he can't post/read news but he can get mail. I will capture the thread and mail to him if you think this seems to have enough interest to post back instead of mailing. ------------------------------------------------------ So what do you think of the following: main() { int i; if ( (i=1) == (i=2) ) { printf( "i'm an ultrix compiler\n" ); } else { printf( "i'm a sun compiler\n" ); } } Is somebody wrong or is the behavior undefined? I didn't look at the sun assembly code, but on the ultrix the comparison seems to have been optimized away (even with the optimizer off). Ultrix seems to say "hey, contents of i equal contents of i so why bother?" Sun seems happy to compare the results of 2 different expressions even though the results are stored in the same place. don. ------------------------------------------------------ Here is my personal opinion along with some more information about various vendors C Compilers. Personal opinion: I think the behaviour is undefined by K&R anyway I can't say for ANSI. VAX C version 3.1 behaves as though it were ultrix. Here are some results on the machines I have access to, just a few flavors of C compilers, I won't dignify the question by trying a PC : On Ultrix 4.1 running on a DECStation 5000/200 $ cd src $ cc -o dontest dontest.c $ dontest i'm an ultrix compiler $ cc -O4 -o dontest dontest.c $ dontest i'm an ultrix compiler $ Now a Sun3 runnning StunOS 4.1 : fpb@ip2_ins1:src 3==>make dontest cc -g -target sun3 -o dontest dontest.c fpb@ip2_ins1:src 4==>dontest i'm a sun compiler OK It knows it's a Sun how about if we optimize fpb@ip2_ins1:src 5==>cc -O -target sun3 -o dontest dontest.c fpb@ip2_ins1:src 6==>dontest i'm an ultrix compiler Ahh now it thinks its ultrix. Now a Sun4 runnning StunOS 4.1 : fpb@ittc:src 112==>cc -target sun4 -o dontest dontest.c fpb@ittc:src 113==>dontest i'm a sun compiler fpb@ittc:src 114==>cc -O -target sun4 -o dontest dontest.c fpb@ittc:src 115==>dontest i'm an ultrix compiler Seems to work just like the sun3 no surprise there. Now lets try the Sun386i running StunOS 4.0.2 : fpb@doccent:src 12==>cc -g -sun386 -o dontest dontest.c fpb@doccent:src 13==>dontest i'm a sun compiler OK optimize fpb@doccent:src 14==>cc -O -sun386 -o dontest dontest.c fpb@doccent:src 15==>dontest i'm a sun compiler Hmmm still Sun, Optimize some more fpb@doccent:src 16==>cc -O3 -sun386 -o dontest dontest.c fpb@doccent:src 17==>dontest i'm a sun compiler Still Sun, Go all the way fpb@doccent:src 18==>cc -O9 -sun386 -o dontest dontest.c cc: Illegal optimization option "-O9" Shoot! OK how about 5 fpb@doccent:src 19==>cc -O5 -sun386 -o dontest dontest.c cc: Illegal optimization option "-O5" Allright 4 fpb@doccent:src 20==>cc -O4 -sun386 -o dontest dontest.c fpb@doccent:src 21==>dontest i'm a sun compiler Still no dice (Oh well noone ever said the 386i had intelligence) Now lets see how the mighty VAX 6530 running VMS 5.4 and using VAX C 3.1 does on this. fpb@kklvx1==>cc dontest.c fpb@kklvx1==>link dontest,sys$library:vaxcrtl/lib fpb@kklvx1==>run dontest i'm an ultrix compiler Hmmmm, perhaps that message should read I am on some sort of DEC machine that likes to optimize easy stuff no matter what. Anyway what do the gods think? -- | () () () | Frank P. Bresz | Westinghouse Electric Corporation | \ /\ / | fpb@ittc.wec.com | ITTC Simulators Department | \/ \/ | uunet!ittc!fpb | Those who can, do. Those who can't, simulate. | ---------- | +1 412 733 6749 | My opinions are mine, WEC doesn't want 'em.
scs@adam.mit.edu (Steve Summit) (06/05/91)
In article <FPB.91Jun4174400@ittc.ittc.wec.com> fpb@ittc.wec.com (Frank P. Bresz) writes: > if ( (i=1) == (i=2) ) > >Is somebody wrong or is the behavior undefined? >Personal opinion: I think the behaviour is undefined by K&R anyway I can't >say for ANSI. Of course it's undefined. (It contains two side effects not separated by a sequence point.) Given that the behavior is undefined, I'd say it's fairly pointless to catalog the behavior of available compilers. As Kernighan and Ritchie point out, and I am fond of quoting, "if you don't know how they are done on various machines, that innocence may help to protect you." The comp.lang.c frequently-asked questions list has a bit to say about undefined order of evaluation. Did you check it first? Steve Summit scs@adam.mit.edu
bard@cutter.ssd.loral.com (J H Woodyatt) (06/05/91)
In article <1991Jun4.233928.5185@athena.mit.edu>, scs@adam.mit.edu (Steve Summit) writes: |> In article <FPB.91Jun4174400@ittc.ittc.wec.com> fpb@ittc.wec.com (Frank P. Bresz) writes: |> > if ( (i=1) == (i=2) ) |> > |> >Is somebody wrong or is the behavior undefined? |> >Personal opinion: I think the behaviour is undefined by K&R anyway I can't |> >say for ANSI. |> |> Of course it's undefined. (It contains two side effects not |> separated by a sequence point.) Is this really undefined by ANSI? I suppose we need someone with the STANDARD to resolve this. (I'm politely assuming that there is a good reason for wanting to though I'm unable to think of one.) My 2nd edition K&R book says in the glossary (p.208) that the result of an assignment expression is the value that was stored in the lvalue after the assignment takes place. Thus, independent of order of evaluation, the above expression should always evaluate FALSE. (Or at least so say I.) The fact that *my* compiler seems to overlook this wording is somewhat alarming to me. I'd like to know what *else* it's willing to ignore, mangle or optimize into oblivion incorrectly. Which leads to an interesting question about portable programming. What fringy kinds of things in a standard can one expect compilers to sometimes overlook and thus be classifiable in the category of `Bad Programming Practice.' __________________________________________________________________ | | James Woodyatt VOICE: (415) 852-5429 | Space Systems/Loral (M/S G87) FAX: (415) 852-6286 | 3825 Fabian Way E-MAIL: bard@cutter.ssd.loral.com | Palo Alto, CA 9430 |
ckp@grebyn.com (Checkpoint Technologies) (06/05/91)
In article <1991Jun4.233928.5185@athena.mit.edu> scs@adam.mit.edu writes: >In article <FPB.91Jun4174400@ittc.ittc.wec.com> fpb@ittc.wec.com (Frank P. Bresz) writes: >> if ( (i=1) == (i=2) ) >> >>Is somebody wrong or is the behavior undefined? >>Personal opinion: I think the behaviour is undefined by K&R anyway I can't >>say for ANSI. > >Of course it's undefined. (It contains two side effects not >separated by a sequence point.) You know, that was my first impression. But after thinking about it, I'm not so sure. You see, I think the (i=1) should evaluate to the value 1, and the (i=2) should evaluate to the value 2, regardless of the order in which they're performed. The order of operations will give the resulting value for i after the if statement. The variable i is not fetched during the entire statement, so the order in which the variable is stored should not matter. Unless someone thinks the compiler should evaluate (i = 1) by storing 1 in i, then fetch that value back some time later for the comparison, but I seem to recall some ANSI rules about how many times a storage object may be touched between sequence points. -- Richard Krehbiel, private citizen ckp@grebyn.com (Who needs a fancy .signature?)
grogers@convex.com (Geoffrey Rogers) (06/05/91)
In article <1991Jun5.014758.10616@wdl1.wdl.loral.com> bard@cutter.ssd.loral.com (J H Woodyatt) writes: >In article <1991Jun4.233928.5185@athena.mit.edu>, scs@adam.mit.edu (Steve Summit) writes: >|> In article <FPB.91Jun4174400@ittc.ittc.wec.com> fpb@ittc.wec.com (Frank P. Bresz) writes: >|> > if ( (i=1) == (i=2) ) >|> > >|> >Is somebody wrong or is the behavior undefined? The behavior of this expression is undefined. Section 3.3 states Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.[34] Footnote 34: 34. This paragraph renders undefined statement expressions such as i = ++i + 1; while allowing i = i + 1; Also you have an evaluation order problem here. Which subexpression do you execute first i=1 or i=2? Again this is undefined. >My 2nd edition K&R book says in the glossary (p.208) that the result of an >assignment expression is the value that was stored in the lvalue after the >assignment takes place. Thus, independent of order of evaluation, the above >expression should always evaluate FALSE. (Or at least so say I.) Remember the operators = and == do not have sequence points. >The fact that *my* compiler seems to overlook this wording is somewhat alarming >to me. I'd like to know what *else* it's willing to ignore, mangle or optimize >into oblivion incorrectly. Since the behavior is undefined for this code fragment, you can expect any two different compilers to gave you different results. >Which leads to an interesting question about portable programming. What fringy >kinds of things in a standard can one expect compilers to sometimes overlook and >thus be classifiable in the category of `Bad Programming Practice. Anything behavior that is explicitly or implicitly defined as being undefined (if the behavior is not defined, it is implicitly defined as beening undefined, atleast this is what a compiler writer told me). cheers +------------------------------------+---------------------------------+ | Geoffrey C. Rogers | "Whose brain did you get?" | | grogers@convex.com | "Abbie Normal!" | | {sun,uunet,uiucdcs}!convex!grogers | | +------------------------------------+---------------------------------+
mcdaniel@adi.com (Tim McDaniel) (06/05/91)
About "if ( (i=1) == (i=2) )": bard@cutter.ssd.loral.com (J H Woodyatt) writes: What fringy kinds of things in a standard can one expect compilers to sometimes overlook and thus be classifiable in the category of `Bad Programming Practice.' Mr. Woodyatt should be more concerned about what HE overlooked: In article <1991Jun4.233928.5185@athena.mit.edu>, scs@adam.mit.edu (Steve Summit) writes: |> The comp.lang.c frequently-asked questions list has a bit to say |> about undefined order of evaluation. Did you check it first? Frequently-Asked Questions section 3, "Order of Evaluation", questions 25 and 26. E-mail me for a copy if it has expired on your system. K&R discuss the subject in section 2.12, "Precedence and Order of Evaluation", pp. 52-54; also A7, "Expressions", paragraph 2, p. 200. (2nd edition, 1st printing.) Look for "side effects" in the index. Also see "C Traps and Pitfalls", by Andrew Koenig -- a fine book. -- "Of course he has a knife; he always has a knife. We all have knives. It's 1183 and we're barbarians." Tim McDaniel Applied Dynamics Int'l.; Ann Arbor, Michigan, USA Internet: mcdaniel@adi.com UUCP: {uunet,sharkey}!amara!mcdaniel
worley@compass.com (Dale Worley) (06/05/91)
In article <1991Jun5.014758.10616@wdl1.wdl.loral.com> bard@cutter.ssd.loral.com (J H Woodyatt) writes: |> > if ( (i=1) == (i=2) ) |> >Is somebody wrong or is the behavior undefined? |> Of course it's undefined. (It contains two side effects not |> separated by a sequence point.) Is this really undefined by ANSI? I suppose we need someone with the STANDARD to resolve this. ANSI C Standard, Dec. 88 draft, sec. 3.3, p. 39, l. 5: Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Why don't people out there just go *buy* a copy of the standard? It would resolve a lot of these questions! Dale Worley Compass, Inc. worley@compass.com -- When asked how much money is enough, Nelson Rockefeller replied: "A little bit more."
volpe@camelback.crd.ge.com (Christopher R Volpe) (06/05/91)
In article <1991Jun5.014758.10616@wdl1.wdl.loral.com>, bard@cutter.ssd.loral.com (J H Woodyatt) writes: |>In article <1991Jun4.233928.5185@athena.mit.edu>, scs@adam.mit.edu (Steve Summit) writes: |>|> In article <FPB.91Jun4174400@ittc.ittc.wec.com> fpb@ittc.wec.com (Frank P. Bresz) writes: |>|> > if ( (i=1) == (i=2) ) |>|> > |>|> >Is somebody wrong or is the behavior undefined? |>|> >Personal opinion: I think the behaviour is undefined by K&R anyway I can't |>|> >say for ANSI. |>|> |>|> Of course it's undefined. (It contains two side effects not |>|> separated by a sequence point.) |> |>Is this really undefined by ANSI? I suppose we need someone with the STANDARD to |>resolve this. (I'm politely assuming that there is a good reason for wanting to |>though I'm unable to think of one.) |> |>My 2nd edition K&R book says in the glossary (p.208) that the result of an |>assignment expression is the value that was stored in the lvalue after the |>assignment takes place. Thus, independent of order of evaluation, the above |>expression should always evaluate FALSE. (Or at least so say I.) Yes, it is undefined according to ANSI. It has nothing to do with order of evaluation, though. You are right about the value of each assignment expression, but that's not the point. The problem, as Steve pointed out, is that the value of "i" is modified twice between sequence points. As a result, all bets are off, since the Standard says that this is not allowed and that anything can happen if you do it. -Chris |>| |>| James Woodyatt VOICE: (415) 852-5429 |>| Space Systems/Loral (M/S G87) FAX: (415) 852-6286 |>| 3825 Fabian Way E-MAIL: bard@cutter.ssd.loral.com |>| Palo Alto, CA 9430 |>| ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
scs@adam.mit.edu (Steve Summit) (06/05/91)
In article <1991Jun5.014758.10616@wdl1.wdl.loral.com> bard@cutter.ssd.loral.com (J H Woodyatt) writes: >In article <1991Jun4.233928.5185@athena.mit.edu>, scs@adam.mit.edu (Steve Summit) writes: >|> Of course it's undefined. (It contains two side effects not >|> separated by a sequence point.) > >Is this really undefined by ANSI? I suppose we need someone with the STANDARD to >resolve this. I *do* have a copy of the Standard. In a (futile) attempt to head this discussion off early, I posted my followup from memory, before going home so that I could quote chapter and verse out of my copy. (Several people have since done so.) I did mention, and you seem to have ignored, my justification (which paraphrases the Standard): "...It contains two side effects not separated by a sequence point." >Which leads to an interesting question about portable programming. What fringy >kinds of things in a standard can one expect compilers to sometimes overlook and >thus be classifiable in the category of `Bad Programming Practice.' This was just mentioned, but it's worth mentioning again: depending on any unspecified or undefined aspects of a language is certainly in the category of "bad programming practice." (Actually, in my own work, I also avoid everything I feel is "fringy," but I realize that's somewhat harder to quantify objectively. As an example, I never depended on free() leaving the contents of freed memory undisturbed, even though old versions of the malloc man page asserted that it did.) K&R is loaded with good advice, although they don't hit you over the head with a brick by setting it off in a sidebar with a header like "Brian & Dennis's Programming Tip #42." Once again, as they say, "if you don't know how [undefined things] are done on various machines, that innocence may help to protect you." In article <1991Jun5.123931.22105@grebyn.com> ckp@grebyn.com writes: >You see, I think the (i=1) should evaluate to the value 1, and the (i=2) >should evaluate to the value 2, regardless of the order in which they're >performed... The variable i is not fetched during the entire >statement, so the order in which the variable is stored should not >matter. Unless someone thinks the compiler should evaluate (i = 1) by >storing 1 in i, then fetch that value back some time later for the >comparison, but I seem to recall some ANSI rules about how many times a >storage object may be touched between sequence points. The rules about how many times a storage object may be "touched" between sequence points (as I recall; my copy of the Standard is still at home) cover: how often a programmer may attempt (in source code) to modify an object, how often a programmer may attempt to access a volatile object, and what code the compiler may generate for volatile objects. They do not make (i = 1) == (i = 2) any less undefined. In fact, it's not at all unreasonable for the compiler to "evaluate (i = 1) by storing 1 in i, then fetch that value back some time later" (this issue was discussed a few months ago, either here or on comp.std.c). Remember that the result of an assignment is the result after assignment, including the cast to the type of the left-hand-side. If we had the code char c1, c2; c1 = c2 = 5.; I would certainly expect the compiler to emit code to convert the value five into a char value, placing the result into c2, and then fetch c2 and place it into c1, rather than doing the conversion twice. Let's try it: Script started on Wed Jun 5 12:12:26 1991 adam> /lib/ccom f() { char c1, c2; c1 = c2 = 5.; cvtlb $5,-2(fp) movb -2(fp),-1(fp) } ret This is on a VAX (which has nice readable instruction mnemonics); I've elided the subroutine preamble from the output. The compiler didn't bother to emit a floating-point constant or a run-time floating-point conversion, but rather a longword (integral) 5 and a convert-longword-to-byte instruction. As expected, it then re-fetches c2 (stored at -2(fp)) before moving the (byte) value to c1 (-1(fp)). There's nothing magic or devious going on here. pcc is not an aggressively-optimizing compiler; this fetch-after-store is in fact a very natural way for a compiler to handle the value of an assignment statement. (A C interpreter I once wrote did the same thing, although there's a note in the source code indicating that it caused me problems when I was attempting to assign to device registers with funny read/write semantics, particularly because the interpreter always fetched the result of an assignment whether it was needed or not.) Of course, we really don't need to think in detail about how assignments are performed to answer the original question. Since the expression in question contains two side effects between sequence points, its behavior is undefined [note 1], and the compiler is free to <insert favorite ludicrous prove-a-point weird undefined compiler behavior>, no matter how "unreasonable." Steve Summit scs@adam.mit.edu Note 1 (again from memory): the behavior of (i = 1) == (i = 2) is undefined, though it is not required to elicit a diagnostic, because it violates a "shall" statement outside of a constraint. Anyone who desires references for any of the assertions made in this article may send me mail; I'll respond to them when I have a copy of the Standard handy.
DOCTORJ@SLACVM.SLAC.STANFORD.EDU (Jon J Thaler) (06/06/91)
In article <1991Jun4.233928.5185@athena.mit.edu>, scs@adam.mit.edu (Steve Summit) says: >> [...discussion of this expression deleted...] >> if ( (i=1) == (i=2) ) >Of course it's undefined. (It contains two side effects not >separated by a sequence point.) Given that the behavior is >undefined, I'd say it's fairly pointless to catalog the behavior >of available compilers. As Kernighan and Ritchie point out, and >I am fond of quoting, "if you don't know how they are done on >various machines, that innocence may help to protect you." When must a compiler issue warnings or other error messages? It seems to me that since this expression is recognizable as an error, a compiler 'ought' to warn the user. As far as I can tell, this does not seem to be required by the standard.
henry@zoo.toronto.edu (Henry Spencer) (06/06/91)
In article <91156.095107DOCTORJ@SLACVM.SLAC.STANFORD.EDU> DOCTORJ@SLACVM.SLAC.STANFORD.EDU (Jon J Thaler) writes: >>> if ( (i=1) == (i=2) ) > >When must a compiler issue warnings or other error messages? It seems to >me that since this expression is recognizable as an error, a compiler >'ought' to warn the user. As far as I can tell, this does not seem to be >required by the standard. The problem is that the references to the same variable may be done via pointers etc., and might be very difficult to recognize at compile time. So it is not realistic to demand that a compiler diagnose all violations of this particular rule. Of course, it is nice if it *does* diagnose them when it notices them. In general, most any "undefined" item in the standard is something that a good compiler ought to *try* to notice and report. The only requirement the standard puts on diagnostics is that a program which violates the standard's official constraints shall draw at least one complaint. Implementations vary so enormously (consider compilers vs. interpreters, for example) that it was not considered practical to set any more specific requirements. -- "We're thinking about upgrading from | Henry Spencer @ U of Toronto Zoology SunOS 4.1.1 to SunOS 3.5." | henry@zoo.toronto.edu utzoo!henry
fpb@ittc.wec.com (Frank P. Bresz) (06/06/91)
In article <1991Jun5.014758.10616@wdl1.wdl.loral.com> bard@cutter.ssd.loral.com (J H Woodyatt) writes: [ some of the thread removed ] >Is this really undefined by ANSI? I suppose we need someone with the STANDARD to >resolve this. (I'm politely assuming that there is a good reason for wanting to >though I'm unable to think of one.) I am guessing you mean why in heaven's name do I want to do this, when it's blatantly ridiculous. Well actually since the post is for a friend I don't, and in fact neither does he. He is using C++ and this code is generated for him from the C++ preprocessor. (AT&T I think). He is however C literate (unlike some others in his organization), and delved into the generated C to try and decide why their code was behaving differently on 2 different machines. This is a small test he created showing the problem. The other C++ people in his group of course thought that clearly one of the compiler vendors must be wrong and that they should be able to call someone to get this fixed (yes corporate mindset). He wanted to isolate it to a programmer misunderstanding (which it is). On the C++ side it was not as blatantly ridiculous (or so he tells me). Thank you all very much. -- | () () () | Frank P. Bresz | Westinghouse Electric Corporation | \ /\ / | fpb@ittc.wec.com | ITTC Simulators Department | \/ \/ | uunet!ittc!fpb | Those who can, do. Those who can't, simulate. | ---------- | +1 412 733 6749 | My opinions are mine, WEC doesn't want 'em.
bard@cutter.ssd.loral.com (J H Woodyatt) (06/07/91)
In article <20273@crdgw1.crd.ge.com>, volpe@camelback.crd.ge.com (Christopher R Volpe) writes: |> In article <1991Jun5.014758.10616@wdl1.wdl.loral.com>, |> bard@cutter.ssd.loral.com (J H Woodyatt) writes: |> |>In article <1991Jun4.233928.5185@athena.mit.edu>, scs@adam.mit.edu |> (Steve Summit) writes: |> |>|> In article <FPB.91Jun4174400@ittc.ittc.wec.com> fpb@ittc.wec.com |> (Frank P. Bresz) writes: |> |>|> > if ( (i=1) == (i=2) ) |> |>|> > |> |>|> >Is somebody wrong or is the behavior undefined? |> |>|> >Personal opinion: I think the behaviour is undefined by K&R anyway |> I can't |> |>|> >say for ANSI. |> |>My 2nd edition K&R book says in the glossary (p.208) that the result of an |> |>assignment expression is the value that was stored in the lvalue after the |> |>assignment takes place. Thus, independent of order of evaluation, the above |> |>expression should always evaluate FALSE. (Or at least so say I.) |> |> Yes, it is undefined according to ANSI. It has nothing to do with order |> of evaluation, though. You are right about the value of each assignment |> expression, but that's not the point. The problem, as Steve pointed out, |> is that the value of "i" is modified twice between sequence points. As |> a result, all bets are off, since the Standard says that this is not allowed |> and that anything can happen if you do it. |> |> -Chris |> |> |>| |> |>| James Woodyatt |> |> ================== |> Chris Volpe |> G.E. Corporate R&D |> volpecr@crd.ge.com <<This is a response to several posts. The above is a general reference.>> I might submit to you that all bets are off concerning the value stored in `i' after the expression is evaluated, but as for the result of the expression, if *that* is undefined, then it isn't by any means intuitive. And, by the way, I *have* a copy of the FAQ, and I *have* read it. I am quite aware of the problem of side effects with order of evaluation; I think the side effect in the above expression renders the value of `i' undefined, *not* the result of the expression. I also have a related question. Given the following: extern volatile int k; if (k = 1) /* Yes, this is an assignment, not an equivalence test */ { .... } I would expect that it is undefined whether the block after the `if' expression will be executed. Am I right? __________________________________________________________________ | | James Woodyatt VOICE: (415) 852-5429 | Space Systems/Loral (M/S G87) FAX: (415) 852-6286 | 3825 Fabian Way E-MAIL: bard@cutter.ssd.loral.com | Palo Alto, CA 9430 |
torek@elf.ee.lbl.gov (Chris Torek) (06/07/91)
[Original code contained two stores to the variable `i' without an intevening sequence point.] >>... all bets are off, since the Standard says that this is not allowed >>and that anything can happen if you do it. In article <1991Jun7.011938.11342@wdl1.wdl.loral.com> bard@cutter.ssd.loral.com (J H Woodyatt) writes: >I might submit to you that all bets are off concerning the value stored >in `i' after the expression is evaluated, but as for the result of the >expression, if *that* is undefined, then it isn't by any means intuitive. Perhaps so; but when the result of an operation is undefined (as here), the behaviour of the system may be completely arbitrary. A compiler is entirely free to compile if ((i = 1) == (i = 2)) printf("hey\n"); as if it were printf("you dummy!\n"); >And, by the way, I *have* a copy of the FAQ, and I *have* read it. I am >quite aware of the problem of side effects with order of evaluation; I >think the side effect in the above expression renders the value of `i' >undefined, *not* the result of the expression. Nope. The whole thing is undefined. The system is allowed to turn into a skunk, or fly to the moon. *ANY*thing might happen (although betting on one of the preceding possibilities is unwise :-) ). >I also have a related question. Given the following: > >extern volatile int k; >if (k = 1) /* Yes, this is an assignment, not an equivalence test */ > { .... } > >I would expect that it is undefined whether the block after the `if' >expression will be executed. Am I right? No and yes. The value of an assignment is the value of the right hand side, converted to the type of the left hand side. In particular, this strongly suggests---it cannot `mean' as the `meaning' of volatile is up to the implementation, but it can calmly `suggest' while swaying a ten ton mallet over the implementation's head---this suggests that, given int i; volatile int *p; i = *p = 3; `i' should have the value 3, and the generated code should store a value at *p but not read any value from *p. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
mouse@thunder.mcrcim.mcgill.edu (der Mouse) (06/07/91)
In article <WORLEY.91Jun5102646@sn1987a.compass.com>, worley@compass.com (Dale Worley) writes: > Why don't people out there just go *buy* a copy of the standard? It > would resolve a lot of these questions! In my case, because I feel I shouldn't have to. der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
mcdaniel@adi.com (Tim McDaniel) (06/07/91)
In article <1991Jun7.011938.11342@wdl1.wdl.loral.com> bard@cutter.ssd.loral.com (J H Woodyatt) writes: I might submit to you that all bets are off concerning the value stored in `i' after the expression is evaluated, but as for the result of the expression, if *that* is undefined, then it isn't by any means intuitive. (*) Not intuitive *to Mr. Woodyatt*. *I* find the ANSI C rule quite intuitive. (*) Who says that anything in C has to be "intuitive"? I suggest that one better guideline is "simple to remember", which is related to but not the same as "intuitive". Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. [ANS C, section 3.3] is simple to remember. (*) For the code in question, the code sequence (for a hypothetical memory-to-memory machine) MOV.I &i,#1 MOV.I &i,#2 CMP &i,&i is intuitive to me, and certainly legal by the standard. The intent of the standard is that compiler don't have to worry about multiple assignments between sequence points -- a considerable freedom. What about (*p = 1) == (*q = 2) ? It could take a lot of compiler work, in the general case, to get what Mr. Woodyatt call the "intuitive" result. Code that uses pointers could be utterly crippled (rather than partially crippled on parallel machines, as is the case in C now). -- "Of course he has a knife; he always has a knife. We all have knives. It's 1183 and we're barbarians." Tim McDaniel Applied Dynamics Int'l.; Ann Arbor, Michigan, USA Internet: mcdaniel@adi.com UUCP: {uunet,sharkey}!amara!mcdaniel
bard@cutter.ssd.loral.com (J H Woodyatt) (06/08/91)
The pummeling I've been receiving in the mail concerning my confusion over exactly what the ANSI standard says about assignment operations has led me to gather my thoughts (somewhat) and ask the question I suppose is at the bottom of my trouble. Here it is: ``When it says that the resulting value of an assignment expression is the value stored in the left operand after the assignment has taken place, does that mean the value *written* to the left operand, or the value that is read (some time before the next sequence point) from the object described by the left operand after the write has been performed?'' It's a subtle point, but it troubles me nonetheless. I figure that the standard either explicitly states that it's the former, it's the latter, it explicitly leaves it to the implementation, or it is curiously silent on the matter. And, I would like to know which (without having to go out and buy a bleeding copy of the bleeding standard). The mail I've been getting implies that it is explicitly left to the imple- mentation of the compiler. Is this the case? -- __________________________________________________________________ | | James Woodyatt VOICE: (415) 852-5429 | Space Systems/Loral (M/S G87) FAX: (415) 852-6286 | 3825 Fabian Way E-MAIL: bard@cutter.ssd.loral.com | Palo Alto, CA 9430 |
jon@maui.cs.ucla.edu (Jonathan Gingerich) (06/08/91)
Having raised exactly this subject several months ago, let me point out that both sides are making valid points. There are two distinct things going on: 1. The description of the value of an assignment expression is sufficiently ambiguous in both K&RI and ANSI as to make the variability of ((i=1)==(i=2)) a reasonable question. This is not directly answered in the FAQ. It is not a `order of evaluation' question. It is not obvious. 2. There is no question that there is a rule in ANSI only, which says that expression which access the same location more than once are undefined. The above expression is undefined as is any other expression (to the best of my knowledge) that would illustrate a difference in the evaluation of an assignment expression. Jon.
torek@elf.ee.lbl.gov (Chris Torek) (06/10/91)
In article <14011@dog.ee.lbl.gov> I wrote, in part: >... The value of an assignment is the value of the right hand >side, converted to the type of the left hand side. I have since checked the wording of the standard, and it does not say this at all. Indeed, it almost (but does not quite) imply the opposite. Since this really only matters with respect to `volatile', and since volatile is implementation-defined anyway, it turns out that one can say nothing at all about how a = b = c; statements work, beyond this: if a and b are aliases for the same object (e.g., if a and b are replaced with *p and *q respectively, and p and q both point to the same object), all bets are off. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
pgheit01@ulkyvx.bitnet (06/14/91)
In article <1991Jun7.232119.17834@cs.ucla.edu>, jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: > Having raised exactly this subject several months ago, let me point out > that both sides are making valid points. There are two distinct things > going on: > > 1. The description of the value of an assignment expression is sufficiently > ambiguous in both K&RI and ANSI as to make the variability of > ((i=1)==(i=2)) > a reasonable question. This is not directly answered in the FAQ. It is > not a `order of evaluation' question. It is not obvious. > > 2. There is no question that there is a rule in ANSI only, which says that > expression which access the same location more than once are undefined. > The above expression is undefined as is any other expression (to the > best of my knowledge) that would illustrate a difference in the evaluation > of an assignment expression. > > Jon. AAAAAARRRRRGGGGHHHHH! Here's how ANSI C works. An expression (ANY EXPRESSION) returns a value in much the same way as a function returns a value. The expression (i = 2) returns the value 2. The expression (i = 1) returns the value 1. No if's, and's or entry points or any of that stuff. The statement if ((i = 1) == (i = 2)) is valid. ANSI C evaluates conditions from left to right. *ALWAYS* ANSI C short-circuits a conditional statement *ALWAYS* (unless you tell it not to) That makes possible the type of statment if ((x != 0) && (1/x < 9)) STATMENT; (note that the inner sets of parentheses are not needed, and "< 9" could be changed to whatever you need to test. Also "x != 0" can just be "x".) ANSI guarratees that the second statement will not be executed(and division by zero will not result) because the statment is false after the first condition if x == 0. I did compile and run the code in question. The assignments do take place. i takes on the value 1 after the first condition is "tested", and i takes on the value 2 after the second condition is tested. After the if-statement is executed, i is and will irrepairably be 2. My C teacher just loved to slip in questions like this one to see if anyone knew the finer details of the precedence table. :-) Paul == pgheit01@ulkyvx.bitnet Disclaimer: How could U of L really accept anything this well-defined as an official policy?
volpe@camelback.crd.ge.com (Christopher R Volpe) (06/14/91)
In article <1991Jun13.184843.508@ulkyvx.bitnet>, pgheit01@ulkyvx.bitnet writes: |> |>Here's how ANSI C works. An expression (ANY EXPRESSION) returns a value in |>much the same way as a function returns a value. Really? Expressions "yield" values. Functions "return" them. The mechanism is probably not all that similar, although this is an unimportant point right now. |> The expression (i = 2) |>returns the value 2. The expression (i = 1) returns the value 1. No if's, |>and's or entry points or any of that stuff. Not relevant. |> |>The statement if ((i = 1) == (i = 2)) is valid. No it's not. RTFS. |>ANSI C evaluates conditions |>from left to right. No. It evaluates the left operand of a "||" or "&&" operator before the right operand. But it's perfectly free to evaluate the right operand of "==" before the left operand. Of course, order of evaluation is not even the issue here anyway. The issue is assignment semantics. An implementation is free to do the following operations: Store 2 in i. Store 1 in i. Get value of i as first operand. Get value of i as second operand. Compare fist operand to second operand. |> *ALWAYS* ANSI C short-circuits a conditional statement Irrelevant. There is no short circuiting in "((i=1) == (i=2))". |>*ALWAYS* (unless you tell it not to) How do you tell it not to short circuit "&&" or "||"??? You can't. |>That makes possible the type of statment |> |>if ((x != 0) && (1/x < 9)) |> STATMENT; |>(note that the inner sets of parentheses are not needed, and "< 9" could be |>changed to whatever you need to test. Also "x != 0" can just be "x".) What are you talking about? The above statement is correct, but has absolutely nothing to do with this discussion. |> |>ANSI guarratees that the second statement will not be executed(and division by |>zero will not result) because the statment is false after the first condition |>if x == 0. Again, so what? |>I did compile and run the code in question. The assignments do take place. Oh good. "Proof by example". |>i takes on the value 1 after the first condition is "tested", and i takes on |>the value 2 after the second condition is tested. After the if-statement is |>executed, i is and will irrepairably be 2. Lucky you. The behavior is undefined. It can do anything, including what you'd like it to do. Just don't rely on it. |>My C teacher just loved to slip in questions like this one to see if anyone |>knew the finer details of the precedence table. :-) Good. Now that you're an expert on operator precedence you can learn the finer details of assignment semantics. ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
fin@norge.unet.umn.edu (Craig A. Finseth) (06/14/91)
In article <1991Jun13.184843.508@ulkyvx.bitnet> pgheit01@ulkyvx.bitnet writes: >In article <1991Jun7.232119.17834@cs.ucla.edu>, jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >> 1. The description of the value of an assignment expression is sufficiently >> ambiguous in both K&RI and ANSI as to make the variability of >> ((i=1)==(i=2)) >> a reasonable question. This is not directly answered in the FAQ. It is >> not a `order of evaluation' question. It is not obvious. >> >> 2. There is no question that there is a rule in ANSI only, which says that >> expression which access the same location more than once are undefined. >> The above expression is undefined as is any other expression (to the >> best of my knowledge) that would illustrate a difference in the evaluation >> of an assignment expression. >AAAAAARRRRRGGGGHHHHH! >Here's how ANSI C works. An expression (ANY EXPRESSION) returns a value in >much the same way as a function returns a value. The expression (i = 2) ... Correct. >The statement if ((i = 1) == (i = 2)) is valid. ANSI C evaluates conditions Not correct. Even though the sub-parts of the expression, taken separately, are valid, it does not follow that the entire statement is valid. >from left to right. *ALWAYS* ANSI C short-circuits a conditional statement >*ALWAYS* (unless you tell it not to) That makes possible the type of statment [ Digression about short-circuit evaluation of && and || and precendence omitted. Irrelevant to this question. ] >I did compile and run the code in question. The assignments do take place. >i takes on the value 1 after the first condition is "tested", and i takes on >the value 2 after the second condition is tested. After the if-statement is >executed, i is and will irrepairably be 2. ANSI says that the expression is undefiend. A compiler behaving as you described does not violate the standard. When arguing that a particular behavior should be defined, it is *never* useful to cite any particular implementation or collection of implementations. >My C teacher just loved to slip in questions like this one to see if anyone >knew the finer details of the precedence table. :-) I'm glad that your teacher is concentrating on these pressing issues. He or she certainly wouldn't want to get involved in such messy issues as what it means to conform to standards, the meaning of "undefined," or other portability-related issues. [Many (:-)s for those of you who couldn't deduce them from the wording.] Craig A. Finseth fin@unet.umn.edu [CAF13] Networking Services +1 612 624 3375 desk University of Minnesota +1 612 625 0006 problems 130 Lind Hall, 207 Church St SE +1 612 626 1002 FAX Minneapolis MN 55455-0134, USA
sa1z+@andrew.cmu.edu (Sudheer Apte) (06/14/91)
pgheit01@ulkyvx.bitnet writes: > > [...] AAAAAARRRRRGGGGHHHHH! [...] > > The statement if ((i = 1) == (i = 2)) is valid. ANSI C evaluates > conditions from left to right. *ALWAYS* ANSI C short-circuits a > conditional statement *ALWAYS* (unless you tell it not to) Hmm. Since you'll probably be flamed out of existence for this, I won't bother. (In case you haven't yet figured it out, '==' is not guaranteed anywhere to evaluate left-to-right. Your second example [deleted] doesn't use '==', and is correct.) I just have a suggestion to make to Steve Summit: do you think this is a good question to put in the FAQ? I vote to put it in. Thanks, Sudheer. ---------------- ...{harvard, uunet}!andrew.cmu.edu!sa1z sa1z%andrew.cmu.edu@CARNEGIE
tim@proton.amd.com (Tim Olson) (06/14/91)
In article <1991Jun13.184843.508@ulkyvx.bitnet> pgheit01@ulkyvx.bitnet writes: | AAAAAARRRRRGGGGHHHHH! | | The statement if ((i = 1) == (i = 2)) is valid. ANSI C evaluates conditions | from left to right. *ALWAYS* ANSI C short-circuits a conditional statement | *ALWAYS* (unless you tell it not to) That makes possible the type of statment | if ((x != 0) && (1/x < 9)) | STATMENT; | (note that the inner sets of parentheses are not needed, and "< 9" could be | changed to whatever you need to test. Also "x != 0" can just be "x".) | | ANSI guarratees that the second statement will not be executed(and division by | zero will not result) because the statment is false after the first condition | if x == 0. There are a number of fallacies in the statement above. The expression ((i=1) == (i=2)) is not valid, because the ANSI spec specifies that (3.3 EXPRESSIONS): "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression." Furthermore, the spec states that (3.3 EXPRESSIONS): "Except [for operators] (), &&, ||, ?:, and "comma", the order of evaluation of subexpressions and the order in which side effects take place are both unspecified." The == operator is not a short-circuit operator, and the order of evaluation of its operands is undefined. | I did compile and run the code in question. The assignments do take place. | i takes on the value 1 after the first condition is "tested", and i takes on | the value 2 after the second condition is tested. After the if-statement is | executed, i is and will irrepairably be 2. That is not a proof, it is just an example. Here is a counterexample: ;1 |int i; ;2 | ;3 |f() ;4 |{ ;5 | return ((i=1) == (i=2)); const gr97,_i const gr96,2 ; (0x2) consth gr97,_i store 0,0,gr96,gr97 ;6 |} jmpi lr0 const gr96,1 ; (0x1) Yep -- the compiler generated code to store the value '2' into i, but returned a '1' as the value of the expression. This is valid code for the given expression. | My C teacher just loved to slip in questions like this one to see if anyone | knew the finer details of the precedence table. :-) This has nothing to do with precedence. -- -- Tim Olson Advanced Micro Devices (tim@amd.com) -- -- Tim Olson Advanced Micro Devices (tim@amd.com)
bhoughto@nevin.intel.com (Blair P. Houghton) (06/16/91)
In article <20575@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: >In article <1991Jun13.184843.508@ulkyvx.bitnet>, pgheit01@ulkyvx.bitnet writes: >|>*ALWAYS* (unless you tell it not to) > >How do you tell it not to short circuit "&&" or "||"??? You can't. Not as such, but, ... ( e1 && e2 ) ... is the same as v1 = e1; v2 = e2; ... ( v1 && v2 ) ... If you want the order of evaluation of expressions to be defined, then define the order of evaluation by evaluating them in that order. The language defines many ways to evaluate expressions in a defined order. --Blair "It won't kill you, nor will anyone who has anything better to do laugh at you."
daniel@sdl.mdcbbs.com (06/16/91)
In article <1991Jun13.184843.508@ulkyvx.bitnet>, pgheit01@ulkyvx.bitnet writes: > In article <1991Jun7.232119.17834@cs.ucla.edu>, jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >> Having raised exactly this subject several months ago, let me point out >> that both sides are making valid points. There are two distinct things >> going on: >> >> 1. The description of the value of an assignment expression is sufficiently >> ambiguous in both K&RI and ANSI as to make the variability of >> ((i=1)==(i=2)) >> a reasonable question. This is not directly answered in the FAQ. It is >> not a `order of evaluation' question. It is not obvious. >> >> 2. There is no question that there is a rule in ANSI only, which says that >> expression which access the same location more than once are undefined. >> The above expression is undefined as is any other expression (to the >> best of my knowledge) that would illustrate a difference in the evaluation >> of an assignment expression. >> >> Jon. > > > AAAAAARRRRRGGGGHHHHH! > > Here's how ANSI C works. An expression (ANY EXPRESSION) returns a value in > much the same way as a function returns a value. The expression (i = 2) > returns the value 2. The expression (i = 1) returns the value 1. No if's, > and's or entry points or any of that stuff. > > The statement if ((i = 1) == (i = 2)) is valid. ANSI C evaluates conditions > from left to right. *ALWAYS* ANSI C short-circuits a conditional statement > *ALWAYS* (unless you tell it not to) That makes possible the type of statment > > if ((x != 0) && (1/x < 9)) > STATMENT; > (note that the inner sets of parentheses are not needed, and "< 9" could be > changed to whatever you need to test. Also "x != 0" can just be "x".) > > ANSI guarratees that the second statement will not be executed(and division by > zero will not result) because the statment is false after the first condition > if x == 0. > > I did compile and run the code in question. The assignments do take place. > i takes on the value 1 after the first condition is "tested", and i takes on > the value 2 after the second condition is tested. After the if-statement is > executed, i is and will irrepairably be 2. > > My C teacher just loved to slip in questions like this one to see if anyone > knew the finer details of the precedence table. :-) > > Paul == pgheit01@ulkyvx.bitnet > > Disclaimer: How could U of L really accept anything this well-defined as an > official policy? -- Daniel Dignam Shape Data Limited (McDonnell Douglas) Internet: daniel@sdl.mdcbbs.com 46 Regent Street UUCP: ...!uunet!sdl.mdcbbs.com!daniel Cambridge CB2 1DB Voice: +44 223 316673 Fax: +44 223 316931 United Kingdom
daniel@sdl.mdcbbs.com (06/16/91)
Sorry about the previous posting, got news_edit logical wrong. In article <1991Jun13.184843.508@ulkyvx.bitnet>, pgheit01@ulkyvx.bitnet writes: > The statement if ((i = 1) == (i = 2)) is valid. ANSI C evaluates conditions > from left to right. *ALWAYS* ANSI C short-circuits a conditional statement > *ALWAYS* (unless you tell it not to) That makes possible the type of statment A quick perusal of my ANSI C spec indicates this is not correct. Section 3.3 reads :- "Except as indicated by the syntax or otherwise specified later (for the function call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified." So you are correct about && but not about ==. Section 3.3 also reads "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. (ftnote 25)" "(ftnote 25) This paragraph renders undefined statement expressions such as i = ++i + 1; whilst allowing i = i + 1; " On assigment operators the ansi standard states that "An assigment expression has the value of the left operand after the assignment, but is not an lvalue""..."The side effect of updating the stored value of the left operand shall occur between the previous and the next sequence point." Now my copy of the standard is only a draft, so it may have been updated to cover this rather nasty case. But my guess is that it hasn't. Anyway where does this leave us? My guess is that the value of the the expression in question is completely undefined (as is thevalue stored in i). A straw poll of the 'ANSI' C compilers in house yields the following results for the given code. #include <stdio.h> main(int argc,char **argv) { int i = 0; if ((i = 1) == (i = 2)) { printf("Branch 1, i = %d\n",i); } else { printf("Branch 2, i = %d\n",i); } } Sun :- Branch 1, i = 2 Vax :- Branch 1, i = 2 Apollo :- Branch 1, i = 2 However K&R variants produce different results Sun :- Branch 2, i = 1 Dec Risc:- Branch 1, i = 2 Read these results as you will, to me it merely confirms that exepressions with side effects should be avoided at all costs. Indeed we have developed an in House C variant which produces errors for these sorts of problems. This case is an interesting example of hard to is to provide a 'complete' specification for a piece of code. After all an ANSI C compiler isn't one of the largest pieces of software around. And, if we can't get the specification for something as well defined (obviously not that well defined as a compiler correct, where does that leave us with respect to some of the larger more complex software projects around (air traffic control, fly by wire ......)? Daniel Dignam Shape Data Limited (McDonnell Douglas) Internet: daniel@sdl.mdcbbs.com 46 Regent Street UUCP: ...!uunet!sdl.mdcbbs.com!daniel Cambridge CB2 1DB Voice: +44 223 316673 Fax: +44 223 316931 United Kingdom
torek@elf.ee.lbl.gov (Chris Torek) (06/18/91)
Others have cleared up the rest of this already, but one point remains. To avoid confusion, I will also restate some of the previous corrections. In article <1991Jun13.184843.508@ulkyvx.bitnet> pgheit01@ulkyvx.bitnet writes: >The statement if ((i = 1) == (i = 2)) is valid. Syntactically, yes; semantically, no. >ANSI C evaluates conditions from left to right. False; evaluation proceeds from sequence point to sequence point in an otherwise undefined manner (with some exceptions; see the standard for exact details). The short-circuit boolean-result operators && and || introduce sequence points, so the left hand side of any such operator is evaluated before the right hand side, and evaluation stops as soon as the result is known; but little else can be said. Certainly `left to right' is far too strong a statement. >My C teacher just loved to slip in questions like this one to see if anyone >knew the finer details of the precedence table. :-) Evaluation order and precedence are orthogonal concepts. For instance, consider the order and precedence relations in: i = *p++; Precedence affects the parsing of `*p++' so that it is interpreted as *(p++) and not (*p)++, and (i = (*(p++))) and not (i = *p)++. The most likely evaluation order on many machines, however, is this: tmp = *p; i = tmp; p++; rather than the `direct' but inefficient sequence: tmp = p; p++; tmp = *tmp; i = tmp; You would do future students a great service to go to your C teacher and tell him, her, or it% to obtain and read a copy of X3.159-1989, the ANSI C standard. [%Perhaps the C teacher is a CAI program. `He' alone may be sexist, but `s/he' and variants are animist. Personally, I think we should just give in and use `it' as the generic third-person singular.$] [$If you needed a half-smiley here, you are not reading these footnotes with the proper dry tone. (How do you tell a CAI program to read the standard, anyway?)] Teachers who concentrate on syntax over semantics are probably missing the point. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
steve@taumet.com (Stephen Clamage) (06/18/91)
daniel@sdl.mdcbbs.com writes: > if ((i = 1) == (i = 2)) ... >Read these results as you will, to me it merely confirms that exepressions >with side effects should be avoided at all costs... Not necessarily, but one most certainly should avoid multiple side-effects between sequence points. >This case is an interesting example of hard to is to provide a 'complete' >specification for a piece of code. After all an ANSI C compiler isn't >one of the largest pieces of software around. And, if we can't get the >specification for something as well defined (obviously not that well >defined as a compiler correct, where does that leave us with respect >to some of the larger more complex software projects around >(air traffic control, fly by wire ......)? This is not a difficulty of specification. One could provide required semantics for the above example, but it was a deliberate choice to leave such things undefined. Over-specification would force compiler implementors to generate inefficient code in many cases in order to satisfy the requirements of pathological programs like the above. -- Steve Clamage, TauMetric Corp, steve@taumet.com