Function Argument Evaluation

Colin Plumb ccplumb at rose.uwaterloo.ca
Fri Mar 22 12:42:18 AEST 1991


jdp at 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



More information about the Comp.std.c mailing list