🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c
Article #4410

Re: On sequence points and evaluation order

#4410
From: Jerry Coffin
Date: Fri, 01 Dec 1995 06:47
119 lines
5354 bytes
nickie@cs.cornell.edu (Nikolaos Papaspyrou) wrote:

>I have a couple of questions regarding side effects, order of
>evaluation and the meaning of a "sequence point" in the standard.
>I would appreciate if somebody could take some time to answer...

>Question 1: Consider the following two programs.

>   int i = 0;                     int i = 0;

>   int main () {                  int f () { return (i = 1); }
>      return (i = 1) + i;
>   }                              int main () {
>                                     return f() + i;
>                                  }

>As far as common sense is concerned, the two programs are equivalent.
>I believe the behavior of the program on the left is undefined
>according to the standard, since between two consecutive sequence
>points (before and after the return statement) a write and a read
>operation occur for object "i", and the read operation does not intend
>to calculate the value that the write operation will store.

>The program on the right does exactly the same thing, only there seems
>to be an extra sequence point just before function "f" is called. Now
>the read and write operations do not occur between two successive
>sequence points. Therefore (please correct me in this, for I believe
>this statement is wrong), the behavior of this program is not
>undefined (so what is it?).

Both are undefined - the order of evaluation of `f() + i' is undefined.
The compiler is free to treat it as if you had written either:
int temp = i;
i = temp + f();

or:

f();
i = i + i;

(Or in theory, since this is undefined behavior, it can do anything else
it wants to as well, but generally it'll evaluate the arguments and
produce a result, but you can't predict what it'll be. )

>Question 2: Consider the following similar program.

>   int f () { printf("message 1\n"); return 1; }
>   int g () { printf("message 2\n"); return 2; }

>   int main () {
>      return f() + g();
>   }

>Evaluation order is not specified and therefore we cannot determine
>which message will be printed first. However, behavior is not
>undefined but depends on the implementation.

>Assuming that both programs in the previous question have undefined
>behavior (as I believe it is), why do we consider a call to "printf"
>to be so drastically different from a write operation to a variable?

Because it's a function call, and a sequence point between having
evaluated the arguments to a function, and actually invoking the
function.

>How will we implement "printf" after all? Won't it have to change a
>few global or static objects, since we usually have buffers for
>"stdout"?  And if I implement such a buffer myself, in my own "printf"
>in my own program, will two calls like this have undefined behavior
>because I'm assigning twice to the same variable?

No - there's always a sequence point betwen evaluating the arguments to
a function, and invoking the function.  Therefore, printf is not the
issue here.  The presence or lack of a sequence point is the issue.  If
you have a function call, it forces a sequence point.  If you used
various other things, they force sequence points as well. e.g. if you'd
written:

	f(), i = i + i;

you'd have a perfectly valid, well defined statement.  However, if you
do the more obvious:

	i = f(), i+i;

I believe the result is still technically undefined.  The assignment
operator doesn't force a sequence point, so in theory the compiler could
treat evaluate the i on the left side before or after the entire right
side.  However, from a practical viewpoint, it's pretty hard to assign
the correct value to i until after you figure out what it is, which is
done after the sequence point introduced by the comma operator.  OTOH,
even a little bit of optimization allows the compiler to "know" the
value of `i' before executing the statement, so it could treat this as:
i = 0;
f();

and still be legal. ( I think...)

>Conclusion: If all this is true, it seems like the whole idea of
>unspecified order of evaluation is not well defined. I assume this is
>not the case, so there must be a number of mistakes in my arguments.
>Could you please help me in locating them?

Well, it's a simple situation.  Storing to a variable more than once
between sequence points is undefined.  Some things, including function
call, force sequence points.  Other things don't.  If you have something
that gives undefined results due to storing multiple values to a single
object between sequence points, then certainly introducing a sequence
point (whether by a function call, comma operator, or separating things
into multiple statements) can certainly render the results defined.
(Note: "can" not necessarily "will")
    Later,
    Jerry.

/* I can barely express my own opinions; I certainly can't
 * express anybody else's.
 *
 * The universe is a figment of its own imagination.
 */
Technical Details
Message-ID: <49m4kf$d6v@natasha.rmii.com>
Path: arc1-ca.pugleaf.net!news.rmii.com!usenet
References: <49l428$od0@bolverk.cs.cornell.edu>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!news.rmii.com!usenet
From: jcoffin@rmii.com (Jerry Coffin)
Newsgroups: comp.std.c
Subject: Re: On sequence points and evaluation order
Date: Fri, 01 Dec 1995 06:47:14 GMT
Organization: TAEUS
Message-ID: <49m4kf$d6v@natasha.rmii.com>
References: <49l428$od0@bolverk.cs.cornell.edu>
NNTP-Posting-Host: slip8145.rmii.com
X-Newsreader: Forte Free Agent 1.0.82