jdp@polstra.UUCP (John Polstra) (03/19/91)
Consider the following program:
#include <stdio.h>
int x = 100, y = 200, *p;
main() {
printf("%d %d\n", *(p = &x), *(p = &y));
}
Could a conforming compiler translate this in such a way that the output
of the program is "200 200"?
I believe it could, based on this quote from section 3.3.2.2 of the
October 31, 1988 draft:
The order of evaluation of the function designator, the arguments,
and subexpressions within the arguments is unspecified, but there is
a sequence point before the actual call.
If I understand correctly, it would be valid to evaluate in this order:
"%d %d\n" /* First argument */
(p = &x) /* Subexpression within second argument */
(p = &y) /* Subexpression within third argument */
*p /* Second argument */
*p /* Third argument */
and the resulting output would be "200 200".
Could somebody please support or refute (with accompanying rationale) my
reasoning?
--
John Polstra polstra!jdp@uunet.uu.net
Polstra & Co., Inc. ...!uunet!polstra!jdp
Seattle, Washington USA (206) 932-6482
"Self-knowledge is always bad news." -- John Barth
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/21/91)
In article <7621@polstra.UUCP>, jdp@polstra.UUCP (John Polstra) writes: |>Consider the following program: |> #include <stdio.h> |> int x = 100, y = 200, *p; |> main() { |> printf("%d %d\n", *(p = &x), *(p = &y)); |> } |>Could a conforming compiler translate this in such a way that the output |>of the program is "200 200"? No, it can't. |>I believe it could, based on this quote from section 3.3.2.2 of the |>October 31, 1988 draft: |> |> The order of evaluation of the function designator, the arguments, |> and subexpressions within the arguments is unspecified, but there is |> a sequence point before the actual call. |> |>If I understand correctly, it would be valid to evaluate in this order: |> |> "%d %d\n" /* First argument */ |> (p = &x) /* Subexpression within second argument */ |> (p = &y) /* Subexpression within third argument */ |> *p /* Second argument */ |> *p /* Third argument */ ^^^ These are not in fact the second and third arguments of the function. Stick an asterisk in front of each of the subexpressions you listed above and then you have the second and third arguments. It is not the value of p at the time of the call that is being dereferenced here. It is the result of the assignment expression that is being dereferenced, and that has nothing to do with any side effects that take place anywhere in this example. Nowhere in the example are you "reading" p's value. The value of the expression "(p = &x)" is "&x". Therefore, "*(p = &x)" is "*(&x)" which is x. So, the output has to be "100 200". ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
gwyn@smoke.brl.mil (Doug Gwyn) (03/21/91)
In article <17750@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: >So, the output has to be "100 200". Wrong. "200 200" is a possible output from a conforming implementation. I thought the cited section of the standard was unusually clear about this.
steve@taumet.com (Stephen Clamage) (03/22/91)
jdp@polstra.UUCP (John Polstra) writes: | #include <stdio.h> | int x = 100, y = 200, *p; | main() { | printf("%d %d\n", *(p = &x), *(p = &y)); | } |Could a conforming compiler translate this in such a way that the output |of the program is "200 200"? |I believe it could, based on this quote from section 3.3.2.2 of the |October 31, 1988 draft: | The order of evaluation of the function designator, the arguments, | and subexpressions within the arguments is unspecified, but there is | a sequence point before the actual call. The statement is identical in the final standard, and is the reason why your example shows a legal result. Legal results from this example are 200 200 with evaluation order p=&x p=&y push(*p) push(*p) 100 100 with evaluation order p=&y p=&x push(*p) push(*p) 100 200 with evaluation order p=&x push(*p) p=&y push(*p) 200 100 with evaluation order p=&y push(*p) p=&x push(*p) -- Steve Clamage, TauMetric Corp, steve@taumet.com
ccplumb@rose.uwaterloo.ca (Colin Plumb) (03/22/91)
jdp@polstra.UUCP (John Polstra) wrote: >Consider the following program: > > #include <stdio.h> > > int x = 100, y = 200, *p; > > main() { > printf("%d %d\n", *(p = &x), *(p = &y)); > } > >Could a conforming compiler translate this in such a way that the output >of the program is "200 200"? The behaviour of this program is undefined (i.e. it could core dump or start singing the Hallelujah chorus - see section 1.6). Your logic is not quite correct. (I retract this below, based on my finding something unexpected in the standard.) >I believe it could, based on this quote from section 3.3.2.2 of the >October 31, 1988 draft: > > The order of evaluation of the function designator, the arguments, > and subexpressions within the arguments is unspecified, but there is > a sequence point before the actual call. > >If I understand correctly, it would be valid to evaluate in this order: > > "%d %d\n" /* First argument */ > (p = &x) /* Subexpression within second argument */ > (p = &y) /* Subexpression within third argument */ > *p /* Second argument */ > *p /* Third argument */ > >and the resulting output would be "200 200". H'm... you know, I never noticed that in the standard before. I have the December 7, 1988 draft with me, and it says, in section 3.3.16, "An assignment expression has the value of the left operand after the assignment..." This is not necessarily the same as the value assigned to the left operand, if the left operand is volatile. Does this mean that every write to a volatile object must be followed by a read? That's obviously wrong, but I can't interpret the wording any other way. Does the final standard say the same thing? >Could somebody please support or refute (with accompanying rationale) my >reasoning? Anyway, ignoring that diversion (which upholds your reasoning; I was wrong), there's also the fact that the wording in 3.3.2.2 suggests to me that there is not a sequence point between (p = &x) and (p = &y). Section 3.3, paragraph 2, is key: "Between the previous and next sequence point an object shall have its 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." Section 1.6 says that if the standard says "shall", anything that doesn't is undefined. I think this means that your code fragment is undefined because it assigns p twice without an intervening sequence point. -- -Colin
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/22/91)
In article <15538@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes: |>In article <17750@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: |>>So, the output has to be "100 200". |> |>Wrong. "200 200" is a possible output from a conforming implementation. |>I thought the cited section of the standard was unusually clear about this. Ok, but I believe that is true only because the behavior is undefined (a fact which I missed until I saw Colin's post), right? I mean, the only reason "200 200" is a possible output in this case is because "Happy new year!" is also a possible output, not because of the original author's reasoning about the value of 'p' at the time of the call. I think that's an important distinction, no? Is there a distinction? Is it not true that the value of 'p' is irrelevant when the actual argument is the assignment expression 'p = &x'? Or am I completely out in left field? ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
gwyn@smoke.brl.mil (Doug Gwyn) (03/23/91)
In article <17809@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: >Ok, but I believe that is true only because the behavior is undefined No; the order of evaluation in this example is explicitly UNSPECIFIED, which is not at all the same as UNDEFINED BEHAVIOR. There are several possible ways to mix up the order of evaluation, but one of them MUST be selected by a conforming implementation for each such situation. (The selection need not be made on a consistent basis, however.)
jon@maui.cs.ucla.edu (Jonathan Gingerich) (03/23/91)
I'm confused. 3 answers have been given to the question. If I understand Doug's last answer, p may be either &x or &y after the statement, but I don't see how this affects the value of (p=&x) and (p=&y) which would remain &x and &y (given the correct type of p). Jon.
bhoughto@pima.intel.com (Blair P. Houghton) (03/23/91)
In article <1991Mar23.014442.24307@cs.ucla.edu> jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >I'm confused. 3 answers have been given to the question. If I understand >Doug's last answer, p may be either &x or &y after the statement, but I >don't see how this affects the value of (p=&x) and (p=&y) which would >remain &x and &y (given the correct type of p). I was confused, too, until I saw the words "and ... subexpressions" blinking out at me from that sentence everyone's posted. It blows away any semblance of stability for the value of p. --Blair "Mine's been gone since I learned Fortran, and that was half a life ago..."
gwyn@smoke.brl.mil (Doug Gwyn) (03/25/91)
In article <1991Mar23.014442.24307@cs.ucla.edu> jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >I'm confused. 3 answers have been given to the question. If I understand >Doug's last answer, p may be either &x or &y after the statement, but I >don't see how this affects the value of (p=&x) and (p=&y) which would >remain &x and &y (given the correct type of p). There is a (possibly apocryphal) story told about Dirac. It seems that he gave a talk on some work he had done, and asked if there were any questions. A member of the audience said "Professor Dirac, I don't understand how you derived that equation." Dirac replied "That is not a question." However, guessing what your question might have been were you to have asked one, I'll point out that the previously cited sentence from the C standard, "The order of evaluation of the function designator, the arguments, and subexpressions within the arguments is unspecified, but there is a sequence point before the actual call", makes it quite clear that a conforming implementation is allowed to interleave evaluation of the two function argument expressions in question. In particular, it can perform both assignments to the variable p before applying the * operator, and thus could obtain the same value for both expressions.
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/25/91)
In article <1991Mar23.014442.24307@cs.ucla.edu>, jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: |>I'm confused. Ditto. |>If I understand |>Doug's last answer, p may be either &x or &y after the statement, but I |>don't see how this affects the value of (p=&x) and (p=&y) which would |>remain &x and &y (given the correct type of p). Ditto, again. |>Jon. ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
jon@maui.cs.ucla.edu (Jonathan Gingerich) (03/26/91)
I once was on a TV high school quiz show. A close friend was on the team too but he was probably stoned that night. Anyway, he was silent the whole night until he hit the buzzer and announced "The Queen of England". "No-o" said the M.C., "the answer is 12 inches". I understand perfectly well that *(p=&x) can be evaluated "after" p has been assigned &y. But does this affect the value of p=&x? I.e. does "the value of the left operand after the assignment" mean "immediately after" or "sometime after, before the next sequence point"? Jon.
msb@sq.sq.com (Mark Brader) (03/26/91)
(It doesn't seem possible to respond to this without a long inclusion; sorry.) John Polstra (jdp@polstra.UUCP): > > #include <stdio.h> > > int x = 100, y = 200, *p; > > main() { > > printf("%d %d\n", *(p = &x), *(p = &y)); > > } > > Could a conforming compiler translate this in such a way that the output > > of the program is "200 200"? # The order of evaluation of the function designator, the arguments, # and subexpressions within the arguments is unspecified, but there is # a sequence point before the actual call. > > If I understand correctly, it would be valid to evaluate in this order: > > > > "%d %d\n" /* First argument */ > > (p = &x) /* Subexpression within second argument */ > > (p = &y) /* Subexpression within third argument */ > > *p /* Second argument */ > > *p /* Third argument */ Chris Volpe (volpecr@crd.ge.com): > ^^^ These are not in fact the second and third arguments of the > function. Stick an asterisk in front of each of the subexpressions you > listed above and then you have the second and third arguments. It is not > the value of p at the time of the call that is being dereferenced here. > It is the result of the assignment expression that is being dereferenced, > and that has nothing to do with any side effects that take place anywhere > in this example. Nowhere in the example are you "reading" p's value. > The value of the expression "(p = &x)" is "&x". Therefore, > "*(p = &x)" is "*(&x)" which is x. Chris is right about the error in John's analysis. The value of an assignment expression is the value of its right-hand operand, converted to the top of its left-hand operand. However, the answer to John's question is still "yes", because of the following clause in 3.3: # 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. Since it doesn't say what happens if you disobey this, the general rule from 1.6 kicks in: # If a "shall" or "shall not" requirement that appears outside of a # constraint is violated, the behavior is undefined. There is also a clarifying footnote to the 3.3 wording: # This paragraph renders undefined statement expressions [sic] such as # i = ++i + 1; # while allowing # i = i + 1; John's program modifies the value of p twice between sequence points, which means it has undefined behavior and a conforming implementation could do *anything* -- generate code that outputs "200 200", refuse to compile the program, invoke rogue, petition the Toronto City Council to rename John Street to Mark Street, etc. Incidentally, if the program does compile in the expected way, it also returns an undefined termination status, since it neither calls exit() nor returns with a value from main(). But this is not "undefined behavior". -- Mark Brader, Toronto "Don't be silly -- send it to Canada" utzoo!sq!msb, msb@sq.com -- British postal worker Original text in this article is in the public domain.
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/26/91)
In article <15552@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes: |>In article <17809@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: |>>Ok, but I believe that is true only because the behavior is undefined |> |>No; the order of evaluation in this example is explicitly UNSPECIFIED, Oh, by the way, Doug, I didn't say the order of evaluation was undefined. I said the behavior of the program itself was undefined (as Colin pointed out). And I'm not saying it's because of any unspecified order of evaluation. It's because the object referenced by p has its value modified more than once between sequence points. (Is this right?) Is it true that the behavior of the program is undefined (for the above reason)? If so, then of course any output is a possible output. If not, then could you explain why the value of p at any given time during execution of that program has any significance whatsoever? Thanks for your patience and help in clarifying this. -Chris ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
dik@cwi.nl (Dik T. Winter) (03/26/91)
In article <17868@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: > In article <1991Mar23.014442.24307@cs.ucla.edu>, jon@maui.cs.ucla.edu > (Jonathan Gingerich) writes: > |>don't see how this affects the value of (p=&x) and (p=&y) which would > |>remain &x and &y (given the correct type of p). > Ditto, again. You both fail to see that the value of (lvalue = expression) is *not* the value of 'expression' before assignment but the value of 'lvalue' after assignment. -- dik t. winter, cwi, amsterdam, nederland dik@cwi.nl
bhoughto@hopi.intel.com (Blair P. Houghton) (03/26/91)
In article <1991Mar25.174542.24419@cs.ucla.edu> jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >I understand perfectly well that *(p=&x) can be evaluated "after" p has been >assigned &y. But does this affect the value of p=&x? I.e. does "the value >of the left operand after the assignment" mean "immediately after" or >"sometime after, before the next sequence point"? The twilight zone: f( *(p = &x), *(p = &y) ); The necessary operations to produce a stack full of arguments: (1) p <-- &x (3) p <-- &y (2) stack <-- *p (4) stack <-- *p The order in which we'd all like to see them performed is, of course, (1) p <-- &x (2) stack <-- *p (3) p <-- &y (4) stack <-- *p but the standard says that the only thing that has to be true is that 2 is later than 1 and 4 is later than 3; this is evident from the parentheses. thus the following cases are also possible: (1) p <-- &x (1) p <-- &x (3) p <-- &y (3) p <-- &y (2) stack <-- *p (4) stack <-- *p (4) stack <-- *p (2) stack <-- *p (3) p <-- &y (3) p <-- &y (1) p <-- &x (1) p <-- &x (2) stack <-- *p (4) stack <-- *p (4) stack <-- *p (2) stack <-- *p (3) p <-- &y (4) stack <-- *p (1) p <-- &x (2) stack <-- *p You could also break it down to the level of (1) addr <-- x (2) p <-- addr (3) value <-- p (4) stack <-- value (5) addr <-- y (6) p <-- addr (7) value <-- p (8) stack <-- value But I'm not going to... Notice that this isn't merely an exercise in unspecificity; it's also an example of the asynchrony of parallelism, and could be a useful exercise in someone's parallel-processing class. --Blair "No copyright. Just send me a copy if you get it right.
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/26/91)
In article <3216@charon.cwi.nl>, dik@cwi.nl (Dik T. Winter) writes: |>You both fail to see that the value of |> (lvalue = expression) |>is *not* the value of 'expression' before assignment but the value of 'lvalue' |>after assignment. Ah. Right. Thank you very much, Dik. Now why couldn't someone have pointed this out before, since that is in fact the root of this confusion. However, isn't this a moot point? The only time the value of 'expression' before assignment may NOT be equal to the value of 'lvalue' after assignment is in the case that 'lvalue' has its contents modified more than once between sequence points, in which case all bets are off. Is this last statement correct? If not, could someone provide a counter-example? (Is the example currently under discussion a counter example?) ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
jimp@cognos.UUCP (Jim Patterson) (03/27/91)
In article <1991Mar25.195234.7179@sq.sq.com> msb@sq.sq.com (Mark Brader) writes: >Chris Volpe (volpecr@crd.ge.com): >> in this example. Nowhere in the example are you "reading" p's value. >> The value of the expression "(p = &x)" is "&x". Therefore, >> "*(p = &x)" is "*(&x)" which is x. > >Chris is right about the error in John's analysis. The value of an >assignment expression is the value of its right-hand operand, converted >to the top of its left-hand operand. You should both read the standard again. Section 3.3.16 Assignment Operators under "Semantics" says: An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the LEFT operand after assignment, but is not an lvalue. [...] The side effect of updating the stored value of the left operand shall occur bgetween the previous and the next sequence point. (emphasis mine, from ANSI X3.159-1989, approved version, page 54) So, *(p=&x) is actually *(p) after assignment, not *(&x), and any of the four results quoted previously is possible. The moral, I guess, is beware of side-effects of parameters. (This has all been pointed out elsewhere; I thought some actual references might help stem this discussion). -- Jim Patterson Cognos Incorporated UUCP:uunet!mitel!cunews!cognos!jimp P.O. BOX 9707 PHONE:(613)738-1440 x6112 3755 Riverside Drive NOT a Jays fan (not even a fan) Ottawa, Ont K1G 3Z4
jon@maui.cs.ucla.edu (Jonathan Gingerich) (03/27/91)
In article <3461@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >In article <1991Mar25.174542.24419@cs.ucla.edu> jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >>I understand perfectly well that *(p=&x) can be evaluated "after" p has been >>assigned &y. But does this affect the value of p=&x? I.e. does "the value >>of the left operand after the assignment" mean "immediately after" or >>"sometime after, before the next sequence point"? > >[A full explanation of how different sequences of the same set of operations > can lead to different results.] Thanks Blair, (and everyone else contributing) I do appreciate the efforts you are making on my behalf. However, and I thought it was plain, I understand your point perfectly well. My question remains 'Does "the value of the left operand after the assignment" mean "immediately after" or "sometime after, before the next sequence point"?' A second question is whether the expression (print statement) is defined to begin with, which would render the above question meaningless, unless it can be reconstructed with a volitile variable. I had thought Doug was claiming the statement was not undefined, but I may have misinterpreted his posting. Jon.
gwyn@smoke.brl.mil (Doug Gwyn) (03/27/91)
In article <17882@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: -In article <15552@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes: -|>In article <17809@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: -|>>Ok, but I believe that is true only because the behavior is undefined -|>No; the order of evaluation in this example is explicitly UNSPECIFIED, -Oh, by the way, Doug, I didn't say the order of evaluation was undefined. -I said the behavior of the program itself was undefined (as Colin -pointed out). And I'm not saying it's because of any unspecified order -of evaluation. It's because the object referenced by p has its value -modified more than once between sequence points. (Is this right?) Sorry, but I cannot make sense out of your use of these terms. They have precise meanings in the context of the C standard, and they have an effect of standard conformance, all explained in Section 1 of the ANSI C standard. -Is it true that the behavior of the program is undefined (for the above -reason)? No, but the output depends on some unspecified aspects of the implementation. I've already explained why, to the best of my ability.
gwyn@smoke.brl.mil (Doug Gwyn) (03/27/91)
In article <1991Mar25.195234.7179@sq.sq.com> msb@sq.sq.com (Mark Brader) writes:
-# 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.
-...
-# If a "shall" or "shall not" requirement that appears outside of a
-# constraint is violated, the behavior is undefined.
OK, Mark may have found a justification for obtaining undefined behavior
out of the example program we've been discussing. This reason is separate
from the (incorrect) ones previously proposed.
In practice I would expect a well-defined result obtained by the
implementation applying a particular ordering to the unspecified
subexpression evaluation, but the program violation of a "shall"
would allow the implementation to behave randomly if it wanted to.
bhoughto@hopi.intel.com (Blair P. Houghton) (03/27/91)
In article <1991Mar26.181821.22912@cs.ucla.edu> jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >Thanks Blair,(and everyone else contributing) You're welcome. >your point perfectly well. My question remains 'Does "the value >of the left operand after the assignment" mean "immediately after" or >"sometime after, before the next sequence point"?' Sequence points (q.v., if you have the Standard handy) define what "after" is. Machines have a tendency to have propagation delays for register transfers and whatnot, so it's not possible for "immediately" to exist; plus, this is a high-level language, and it will be translated into any number of object-level representations. "Before" an operation is a sequence point. "After" an operation is the next sequence point. There is no "after the operation but before the sequence point." >A second question is whether the expression (print statement) is defined to >begin with, which would render the above question meaningless, unless it >can be reconstructed with a volitile variable. I had thought Doug was >claiming the statement was not undefined, but I may have misinterpreted >his posting. You win the Convoluted Paragraph Of The Quarter Prize. I had to solve it to figure out what you could possibly be saying without also being totally bats: If you mean "is the function call guaranteed to occur regardless of the order of evaluation of the arguments," then yes, that is correct. Something will be printed, using the format passed and to the file specified, if their values are not somehow dependent on the order of evaluation. (Here they are, respectively, a string constant (the format), and implied (stdout, the place to which printf(3) prints), so they aren't dependent on a couple of assignments and dereferences). This is true of all functions, not just predefined library routines. To clarify: the machine _must_ evaluate the expressions and call the function; the word "unspecified" merely says that the Standard refuses to insist on a specific order. If the Standard says "the behavior is undefined," then you can start taking bets as to what will happen next. --Blair "Code is to time what topology is to geometry."
torek@elf.ee.lbl.gov (Chris Torek) (03/27/91)
In article <17895@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: >However, isn't this a moot point? The only time the value of 'expression' >before assignment may NOT be equal to the value of 'lvalue' after >assignment is in the case that 'lvalue' has its contents modified more >than once between sequence points, in which case all bets are off. No: one typical case is: unsigned char c; unsigned long l; ... (void) printf("l=%lx c=%x\n", l, (c = l)); which (again, `typically') pushes `l' through a `character knothole' and `scrapes off' the top bits. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
torek@elf.ee.lbl.gov (Chris Torek) (03/27/91)
[this is a correction of a cancelled article, with the word `not' inserted in a strategic location.] In article <1991Mar26.181821.22912@cs.ucla.edu> jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >... My question remains 'Does "the value of the left operand after >the assignment" mean "immediately after" or "sometime after, before >the next sequence point"?' Yes. It also means anything else you can come up with that fits, since it is not pinned down any more precisely. The method by which `the value of the left operand after assignment' is computed is entirely up to the compiler. I would not be surprised to see a compiler turn: char c; int *ip; ... f(*ip++ = c, *ip++ = 0); into: extbl r1, p0 // turn byte in r1 into integer // with result going into `parameter // register 0' stl p0, [r2] // store result through pointer ip clrl p1 // put 0 in parameter register 1 stl p1, [r2] // store result through pointer ip incl 8, r2 // add sizeof 2 ints to pointer ip call _f // and call function -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/27/91)
Thanks to all who pointed out to me that the value of the left operand after assignment (meaning after the next sequence point) may be different from the value of the right operand if the type of the left operand is different from the type of the right operand. For example, the value of "(intvar = 2.3)" is "2", not "2.3". This, however, is not relevant to the question under discussion. The only reason the output of the program in question can be "200 200" is because the BEHAVIOR of the PROGRAM (right Doug?) is undefined because the program violates the "shall" rule in paragraph 2 of 3.3, which is not within a constraint. It is pointless to present a sequence of evaluations of subexpressions in some order to "prove" that the program can print out "200 200". It can print out anything it pleases. ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/27/91)
I am aware of the precise meanings of the terms "undefined" and "unspecified" and I don't think I used either term in a manner inconsistent with those meanings. ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
jon@maui.cs.ucla.edu (Jonathan Gingerich) (03/28/91)
First a sincere thanks to everyone trying to help. Second, a reminder that precision and meticulousness can often be mistaken for pedantry and rudeness, especially if people are not addressing the central issue. Both Christopher and I realize the assignment may cause a type conversion, and we both realize different sequences of operations can have different results. Thank you. You can stop posting such examples now. I originally wanted to satisfy my own curiosity about this and pointed out that the answers so far were not in agreement. I still have a question so let me rephrase it: Is there any situation where the value stored at l can change before (l=r) is evaluated but after the assignment, without causing the program to be undefined? If so, is the value of (l=r) nonetheless restricted to the value of l _immediately_ after the assignment? Jon.
gwyn@smoke.brl.mil (Doug Gwyn) (03/28/91)
In article <17936@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: >The only reason the output of the program in question can be >"200 200" is because the BEHAVIOR of the PROGRAM (right Doug?) is >undefined because the program violates the "shall" rule in paragraph >2 of 3.3, ... NO -- my original argument did NOT rely on undefined behavior. It relied on the unspecified order of evaluation of the subexpressions. Even without the cited "shall" in the standard, "200 200" would have been a valid output (but not "42 3.1416").
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/28/91)
In article <15607@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes: |>In article <17936@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: |>>The only reason the output of the program in question can be |>>"200 200" is because the BEHAVIOR of the PROGRAM (right Doug?) is |>>undefined because the program violates the "shall" rule in paragraph |>>2 of 3.3, ... |> |>NO -- my original argument did NOT rely on undefined behavior. It |>relied on the unspecified order of evaluation of the subexpressions. |>Even without the cited "shall" in the standard, "200 200" would have |>been a valid output (but not "42 3.1416"). But the only reason you were able to produce an order of evaluation that resulted in "200 200" is because the program did something it should never have done in the first place, which was to modify p twice between sequence points. I would be very interested in seeing a program whose behavior was *not* undefined, yet could arbitrarily produce either of two drastically different outputs depending solely on the unspecified order of evaluation. (By "drastically different" I mean something like "100 200" vs. "200 200". I don't mean something like "12.427" vs. "12.426999".) ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/28/91)
In article <9439@cognos.UUCP>, jimp@cognos.UUCP (Jim Patterson) writes: |>So, *(p=&x) is actually *(p) after assignment, not *(&x), and any of the |>four results quoted previously is possible. I believe that in any situation in which the behavior is *not* undefined, there is absolutely no difference between "the value of the left operand after assignment" and "the value of the right operand suitably cast to the type of the left operand". Drawing such a distinction affects things only when something has been done to render the behavior undefined. If there's a counter example to the above paragraph, I'd love to see it. ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
jon@maui.cs.ucla.edu (Jonathan Gingerich) (03/29/91)
In article <3484@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >In article <1991Mar26.181821.22912@cs.ucla.edu> jon@maui.cs.ucla.edu (Jonathan Gingerich) writes: >>your point perfectly well. My question remains 'Does "the value >>of the left operand after the assignment" mean "immediately after" or >>"sometime after, before the next sequence point"?' > >Sequence points (q.v., if you have the Standard handy) define what >"after" is. Machines have a tendency to have propagation delays >for register transfers and whatnot, so it's not possible for >"immediately" to exist; plus, this is a high-level language, and >it will be translated into any number of object-level representations. Un-huh. But I don't care how the machine arrives at the result, only what the result should be. I don't see the language of the Standard suggesting you do the store, then when you want the value of the assignment expression you go look what is stored at the location. Instead you determine what value should be stored and that is the value of the assignment expression regardless of what happens to the location. > >"Before" an operation is a sequence point. "After" an >operation is the next sequence point. There is no >"after the operation but before the sequence point." I am no expert nor do I have the Standard handy, but I am under the strong impression that sequence points determine what subexpressions can be (conceptually) evaluated in random order and what must be evaluated in sequential order. >>A second question is whether the expression (print statement) is defined to >>begin with, which would render the above question meaningless, unless it >>can be reconstructed with a volitile variable. I had thought Doug was >>claiming the statement was not undefined, but I may have misinterpreted >>his posting. > >You win the Convoluted Paragraph Of The Quarter Prize. >I had to solve it to figure out what you could possibly >be saying without also being totally bats: >If you mean "is the function call guaranteed to occur >regardless of the order of evaluation of the arguments," > ... Obviously my statement is confusing as you do not understand it. Perhaps it might be useful to you to go back and read the entire thread. Your last posting also missed the point and I don't want you wasting your time. The concensus is that the original statement had undefined behavior. x = 100; y=200; printf("%d %d", *(p=&x), *(p=&y)) Doug asserts that it could print out '200' '100' by order of evaluation alone. I find the wording about the value of an assignment expression ambiguous enough to be unconvinced, but the point appears moot. Jon.
ed@mtxinu.COM (Ed Gould) (03/29/91)
>I would be very interested in seeing a program whose behavior >was *not* undefined, yet could arbitrarily produce either of two >drastically different outputs depending solely on the unspecified >order of evaluation. Will this do? foo() { int v = 1; printf("%d %d\n", v, ++v); } It may print either 1 2 or 2 2 depending solely on order of evaluation. Are there any other things here that make this program's behavior undefined? I think not. -- Ed Gould mt Xinu, 2560 Ninth St., Berkeley, CA 94710 USA ed@mtxinu.COM +1 415 644 0146 "I'll fight them as a woman, not a lady. I'll fight them as an engineer."
diamond@jit345.swstokyo.dec.com (Norman Diamond) (03/29/91)
In article <17985@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: >In article <9439@cognos.UUCP>, jimp@cognos.UUCP (Jim Patterson) writes: >|>So, *(p=&x) is actually *(p) after assignment, not *(&x), and any of the >|>four results quoted previously is possible. > >I believe that in any situation in which the behavior is *not* undefined, >there is absolutely no difference between "the value of the left operand >after assignment" and "the value of the right operand suitably cast to >the type of the left operand". If the left operand is volatile, the standard says that the value of the right operand gets stored into it. However, it is not quite clear if the left operand is actually required to contain that value (for any finite or infinitesimal length of time). Suppose it's a hardware device which automatically doubles the value stored into it? (Pick a less trivial example for this if you wish.) The question has already been asked, if the left operand is volatile, is the processor required to follow the store with a fetch, in order to use the actually-contained value in the outer expression. The answers given in this newsgroup converged on "No," it was not necessary. But I sure don't understand why. If the fetch isn't done, it sure seems to me that it violates the rules about volatile. -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it.
volpe@camelback.crd.ge.com (Christopher R Volpe) (03/29/91)
In article <1991Mar28.194627.26285@mtxinu.COM>, ed@mtxinu.COM (Ed Gould) writes: |>>I would be very interested in seeing a program whose behavior |>>was *not* undefined, yet could arbitrarily produce either of two |>>drastically different outputs depending solely on the unspecified |>>order of evaluation. |> |>Will this do? |> |> foo() { |> int v = 1; |> |> printf("%d %d\n", v, ++v); |> } No, because before the sequence point that occurs before the call, you are modifying v and using v in a way that is not used to determine the new value of v. See my response to Blair's similar example. (Either shortly before or after this post, depending on how things get randomly rearranged over the net.) |> |>-- |>Ed Gould mt Xinu, 2560 Ninth St., Berkeley, CA 94710 USA |>ed@mtxinu.COM +1 415 644 0146 |> |>"I'll fight them as a woman, not a lady. I'll fight them as an engineer." ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
jon@maui.cs.ucla.edu (Jonathan Gingerich) (03/30/91)
In article <1991Mar28.194627.26285@mtxinu.COM> ed@mtxinu.COM (Ed Gould) writes: >Will this do? > > foo() { > int v = 1; > > printf("%d %d\n", v, ++v); > } The first argument of v reads v without using the value to set v, so this too is undefined. I think "order of evaluation" is a non-issue in ANSI C; 3.3 seems pretty air-tight. Therefore the value of (l=r) is only of interest in K&R(I) were the language is similar to (++x), so it's pretty ambiguous. ANSI C has leap-frogged the whole issue. Jon.