[comp.std.c] Function Argument Evaluation

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.