Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Assignment with Post Increment

28 views
Skip to first unread message

Tony Brown

unread,
Mar 1, 2000, 3:00:00 AM3/1/00
to
We are using the National Instruments ANSI C Compiler (it is part of their
instrument development software) and have come across some unexpected
behaviour relating to post increment coupled with an assignment. The problem
is that

char *index;
....
*index++ = toupper(*index);

is performing the post increment before assigning the new value to (*index),
i.e. it is doing *(index + 1) = toupper(*index); index++;

If index is replaced by index1 and index 2, both preset to the same value,
then

char *index1, index2;
....
*index1++ = toupper(*index2++);

has the expected result (i.e. the character pointed to by index 2 is moved
to the address pointed to by index1, then both pointers are incremented.

The response from NI developer support is

<< This is officially described by the ANSI C standard as undefined
behavior. The assignment and increment operators do not have a set
relationship, so the behavior is indeterministic. There are dozens of such
coding anomalies that have undefined behavior most of which de al with
casting and operators
Basically, you should never do this. This should be done in two lines as:
*index1 = toupper (*index1);
*index1++;
There is no "correct" behavior for instances like these. It is undefined.
>>

I am not convinced by the response. My old original Kernighan & Richie (pre
ANSI) uses assignment with post increment in one of the examples.

I could possibly believe that using the same pointer as both the source and
destination with post increment could be suspect. If NI support is correct,
and you cannot mix assignment with post increment, then I (and a lot of
others) are running a lot of very dubious code.

Does anyone have an opinion on this, or point me to the part in the ANSI
standard which says either this is allowed or not allowed.

Many thanks

Tony Brown
Beran Instruments
England

Douglas A. Gwyn

unread,
Mar 1, 2000, 3:00:00 AM3/1/00
to
Tony Brown wrote:
> *index++ = toupper(*index);

NI's response was misleading; the issue is one of sequence points.

If a macro implementation of toupper is being used, then (probably)
there is no sequence point within that construct. Consequently,
the side effect of the ++ and = operations can occur in various
orders. From what you say the generated code was, *(index+1)...,
NI's compiler also has a horrible bug which confused the issue,
because the result of "index++" is definitely required to be the
value of index before the increment. If it were merely the
sequence point issue, the unexpected behavior would be along the
lines, *(index)=toupper(*(index+1)).

If you force a function implementation of toupper to be used
(which will slow down your program), then there is no longer a
sequence point problem, and the code could be used in a strictly
conforming program. (But watch out for other requirements on
multiple accesses of the same object within an expression, in
other similar-but-different constructs.)

NI's advice to split the two uses of "index" into two statements
(which inserts a sequence point between them) is good advice,
since it permits the continued use of the faster macro version.

Marc van Leeuwen

unread,
Mar 1, 2000, 3:00:00 AM3/1/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:

> Tony Brown wrote:
> > *index++ = toupper(*index);
>

> If a macro implementation of toupper is being used, then (probably)
> there is no sequence point within that construct. Consequently,
> the side effect of the ++ and = operations can occur in various
> orders.

But that is not the problem; the objects affected by those side effects are
distinct (the pointer `index' versus the object it originally pointed to).
Indeed there is absolutely no problem with `*index++=0;'. The problem is
between the read access to `*index' in the right hand side and the write
access to it which is the side effect of `++'. There is no sequence point to
separate those, so the C-standard's most abominable paragraph (the one
containing "only to determine the value to be stored") rears its ugly head and
shouts: undefined.

> [...] If it were merely the


> sequence point issue, the unexpected behavior would be along the
> lines, *(index)=toupper(*(index+1)).
>
> If you force a function implementation of toupper to be used
> (which will slow down your program), then there is no longer a
> sequence point problem, and the code could be used in a strictly
> conforming program.

No, the sequence point problem would still exist. While there would then be a
sequence point after fetching `*index' and before entering into `toupper', it
is not determined that said sequence point would precede the side effect from
`++'. It is completely legal and plausible to complete evaluation of the left
hand side of `=' (holding the address determined in a temporary location),
including its side effect, before starting to evaluate the right hand side;
that would give the `*(index)=toupper(*(index+1))' behaviour. It is obvious
(though not specified in the standard) that the side effect of `=' cannot
happen before the values from both sides are determined (with possibly some
side effects still pending), but that is not the issue in this example.

Marc van Leeuwen
Universite de Poitiers
http://wwwmathlabo.univ-poitiers.fr/~maavl/

Jan Echternach

unread,
Mar 1, 2000, 3:00:00 AM3/1/00
to
In article <87wvnma...@young.sp2mi.univ-poitiers.fr>,

Marc van Leeuwen <ma...@mathlabo.univ-poitiers.fr> writes:
> The problem is
> between the read access to `*index' in the right hand side and the write
> access to it which is the side effect of `++'. There is no sequence point to

Close, but still not correct. *index++ is *(index++). It's the read
access to 'index' and the write access to it which is the side effect
of '++'.

--
Jan

Larry Jones

unread,
Mar 1, 2000, 3:00:00 AM3/1/00
to
Douglas A. Gwyn (DAG...@null.net) wrote:
> Tony Brown wrote:
> > *index++ = toupper(*index);
>
> If you force a function implementation of toupper to be used
> (which will slow down your program), then there is no longer a
> sequence point problem, and the code could be used in a strictly
> conforming program.

No, index is still being modified and used (other than to determine the
new value) with no intervening sequence point, so it's still undefined
behavior.

-Larry Jones

Everything's gotta have rules, rules, rules! -- Calvin

Michael Rubenstein

unread,
Mar 1, 2000, 3:00:00 AM3/1/00
to
On Wed, 01 Mar 2000 10:44:02 GMT, "Douglas A. Gwyn"
<DAG...@null.net> wrote:

>Tony Brown wrote:
>> *index++ = toupper(*index);
>

>NI's response was misleading; the issue is one of sequence points.
>

>If a macro implementation of toupper is being used, then (probably)
>there is no sequence point within that construct. Consequently,
>the side effect of the ++ and = operations can occur in various

>orders. From what you say the generated code was, *(index+1)...,
>NI's compiler also has a horrible bug which confused the issue,
>because the result of "index++" is definitely required to be the

>value of index before the increment. If it were merely the


>sequence point issue, the unexpected behavior would be along the
>lines, *(index)=toupper(*(index+1)).
>

>If you force a function implementation of toupper to be used
>(which will slow down your program), then there is no longer a
>sequence point problem, and the code could be used in a strictly

>conforming program. (But watch out for other requirements on
>multiple accesses of the same object within an expression, in
>other similar-but-different constructs.)
>
>NI's advice to split the two uses of "index" into two statements
>(which inserts a sequence point between them) is good advice,
>since it permits the continued use of the faster macro version.

Do you wish to reconsider your answer?

Even if toupper is implemented as a function, there is no
sequence point (necessarily) between the incrementation and the
evaluation as an argument. An implementation could increment
index and store the new value before evaluating *index for the
argument to toupper.

It would have been better had NI mentioned sequence points, but
their answer is essentially correct. This does produce undefined
behavior.

Keith Thompson

unread,
Mar 1, 2000, 3:00:00 AM3/1/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:
> Tony Brown wrote:
> > *index++ = toupper(*index);
>
> NI's response was misleading; the issue is one of sequence points.
>
> If a macro implementation of toupper is being used, then (probably)
> there is no sequence point within that construct. Consequently,
> the side effect of the ++ and = operations can occur in various
> orders. From what you say the generated code was, *(index+1)...,
> NI's compiler also has a horrible bug which confused the issue,
> because the result of "index++" is definitely required to be the
> value of index before the increment. If it were merely the
> sequence point issue, the unexpected behavior would be along the
> lines, *(index)=toupper(*(index+1)).

But if the statement invokes undefined behavior, anything can happen.
You can't conclude that the compiler has a horrible bug unless you can
demonstrate it in a program that *doesn't* invoke undefined behavior.

--
Keith Thompson (The_Other_Keith) k...@cts.com <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://www.sdsc.edu/~kst>
Welcome to the last year of the 20th century.

Peter Seebach

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
In article <iE5v4.4471$O5.132801@stones>,

Tony Brown <tony_...@beran.co.uk> wrote:
>We are using the National Instruments ANSI C Compiler (it is part of their
>instrument development software) and have come across some unexpected
>behaviour relating to post increment coupled with an assignment. The problem
>is that
>
>char *index;
>....
> *index++ = toupper(*index);
>
>is performing the post increment before assigning the new value to (*index),
>i.e. it is doing *(index + 1) = toupper(*index); index++;

They're right, you're wrong. You are using and modifying 'index' without
an intervening sequence point; you have invoked undefined behavior. Go
directly to potentially surprising results, do not pass go, do not collect
side effects. ;)

-s
--
Copyright 2000, All rights reserved. Peter Seebach / se...@plethora.net
C/Unix wizard, Pro-commerce radical, Spam fighter. Boycott Spamazon!
Consulting & Computers: http://www.plethora.net/
Get paid to surf! No spam. http://www.alladvantage.com/go.asp?refid=GZX636

Douglas A. Gwyn

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Marc van Leeuwen wrote:
> ... so the C-standard's most abominable paragraph (the one containing

> "only to determine the value to be stored") rears its ugly head and
> shouts: undefined.

I considered whether that applied and decided not, in this example.

> > If you force a function implementation of toupper ...


> No, the sequence point problem would still exist. While there would
> then be a sequence point after fetching `*index' and before entering
> into `toupper', it is not determined that said sequence point would
> precede the side effect from `++'.

What on earth are you talking about? The whole point of sequence
points is to determine when side effects have to occur. They
enforce a "sequencing" that is related to the parse order, so the
sequence point at the function call flushes side effects before
the result of the function call is used in the rest of the expression.

Douglas A. Gwyn

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Larry Jones wrote:
> Douglas A. Gwyn (DAG...@null.net) wrote:
> > Tony Brown wrote:
> > > *index++ = toupper(*index);
> > If you force a function implementation of toupper to be used
> > (which will slow down your program), then there is no longer a
> > sequence point problem, and the code could be used in a strictly
> > conforming program.
> No, index is still being modified and used (other than to determine
> the new value) with no intervening sequence point, so it's still
> undefined behavior.

The instance of "index" on the RHS is clearly being used only to
determine the new value to be stored by the assignment operation.
So I assume you're referring to the instance of "index" on the LHS.
In which case, watch out that your argument doesn't also outlaw
*x++ = 1, which I think we all agree should be usable in a strictly
conforming program.

Douglas A. Gwyn

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Michael Rubenstein wrote:
> Even if toupper is implemented as a function, there is no
> sequence point (necessarily) between the incrementation and the
> evaluation as an argument.

The spec says "... there is a sequence point before the actual call".
How do you get from evaluating the argument to using the result of
the function call without passing through at least one sequence point?

Douglas A. Gwyn

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Keith Thompson wrote:
> But if the statement invokes undefined behavior, anything can happen.
> You can't conclude that the compiler has a horrible bug unless you can
> demonstrate it in a program that *doesn't* invoke undefined behavior.

The compiler is a machine that follows certain rules, and if it
produces the result reported, I have to question whether its rules
are correct. I would agree that one should look for a strictly
conforming example before filing a bug report, however.

Dennis Ritchie

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to

In the *index = toupper(*index++) case, maybe by evaluating *index,
a sufficient subexpression for generating the argument's value. Then stash
the LHS index. Then call (sequence point, but the larger arg expression
wasn't evaluated yet). Then store through the stashed version of
the LHS, finally increment index.

Dennis

Douglas A. Gwyn

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Dennis Ritchie wrote:

> "Douglas A. Gwyn" wrote:
> > The spec says "... there is a sequence point before the actual call".
> > How do you get from evaluating the argument to using the result of
> > the function call without passing through at least one sequence point?
> In the *index = toupper(*index++) case, maybe by evaluating *index,
> a sufficient subexpression for generating the argument's value. ...

I agree, for that case, but I thought we were debating the reported
*index++ = toupper(*index) // assumed to be a function call
where a different line of argumentation would have to be found.

Anyway, I understand the sentiment that this is not a very clear
part of the standard, and would like somebody (not me!) to file a
DR on it in order to get an official elaboration of the intended
rules. As the original post showed, this can have practical
implications, so it is worth resolving.

Clive D.W. Feather

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
In article <38BDEA07...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>What on earth are you talking about? The whole point of sequence
>points is to determine when side effects have to occur. They
>enforce a "sequencing" that is related to the parse order, so the
>sequence point at the function call flushes side effects before
>the result of the function call is used in the rest of the expression.

Yes, but evaluating the address to be assigned to is not constrained
with respect to the right hand side. In:

*x = y

there are no sequence points restricting the relative order of the
evaluations of x and y. Even where y involves an internal sequence
point.

--
Clive D.W. Feather | Internet Expert | Work: <cl...@demon.net>
Tel: +44 20 8371 1138 | Demon Internet | Home: <cl...@davros.org>
Fax: +44 20 8371 1037 | Thus plc | Web: <http://www.davros.org>
Written on my laptop; please observe the Reply-To address

Clive D.W. Feather

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
In article <38BE1AFC...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>Anyway, I understand the sentiment that this is not a very clear
>part of the standard, and would like somebody (not me!) to file a
>DR on it in order to get an official elaboration of the intended
>rules.

IIRC there have been several DRs on the topic, none of which got a
workable answer. And there is a new project item sitting with WG14 (I
forget the formal title, but essentially it's another pass over my Annex
S paper).

Michael Rubenstein

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
On Thu, 02 Mar 2000 04:23:21 GMT, "Douglas A. Gwyn"
<DAG...@null.net> wrote:

>Michael Rubenstein wrote:
>> Even if toupper is implemented as a function, there is no
>> sequence point (necessarily) between the incrementation and the
>> evaluation as an argument.
>

>The spec says "... there is a sequence point before the actual call".
>How do you get from evaluating the argument to using the result of
>the function call without passing through at least one sequence point?

But the spec does not say that the right hand side will be
evaluated before the left. Sequence points are a partial, not a
complet, ordering.

The statement in question is

*index++ = toupper(*index);

Nothing in the standard prohibits the following order of
evaluation:

1. Retrieve the value of index and save it.

2. Increment index and store the result.

3. Dereference index, getting the value.

4. Call toupper with the value from 3.

5. Store the result of 4 in the address pointed to by
the value saved from step 1.

There is a sequence point before the actual call, but it need not
come between the increment for the left side and the evaluating
the argument.


Marc van Leeuwen

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
First, I stand corrected by Jan Echternach for saying read access to `*index'
in my previous post when I meant read access to `index'; that was particularly
stupid since I had just been pointing out a similar misunderstanding.

I now realise that part of the confusion is that in the example under
consideration:

*index++ = toupper(*index);

there are two variables being accessed and modified. One is `index' itself,
which is causing undefined behaviour; the other is the variable originally
designated by `*index', which is perfectly innocent and therfore a red
herring. Obviously to uppercase `*index', its prior value must be fetched in
order to determine the new value to be stored; that's OK with or without any
sequence points. However the use of `index' in the argument expression for
`toupper' is completey unrelated to determining the new value to be stored in
`index' as side effect of evaluation `index++'.

"Douglas A. Gwyn" <DAG...@null.net> writes:

> Larry Jones wrote:
> > Douglas A. Gwyn (DAG...@null.net) wrote:
> > > If you force a function implementation of toupper to be used
> > > (which will slow down your program), then there is no longer a
> > > sequence point problem, and the code could be used in a strictly
> > > conforming program.
> > No, index is still being modified and used (other than to determine
> > the new value) with no intervening sequence point, so it's still
> > undefined behavior.
>
> The instance of "index" on the RHS is clearly being used only to
> determine the new value to be stored by the assignment operation.

Yes, but in the phrase "the prior value shall be accessed only to determine
the value to be stored" it is clear that "the value to be stored" is not just
any value to be stored, it is the one that replaces the mentioned prior value.
But in the example the (character or integer) value to be stored by the
assignement operartor is not replacing the (pointer) value of `index'.

> So I assume you're referring to the instance of "index" on the LHS.
> In which case, watch out that your argument doesn't also outlaw
> *x++ = 1, which I think we all agree should be usable in a strictly
> conforming program.

Yes we do. In fact there would be no problem if it could be guaranteed that
the prior value of `index' is only once accessed during evaluation; however
since the variable is spelled out twice, it will be accessed twice in the
abstract machine, so one cannot force an implementation to access it just
once. Here's a rewrite that attempts to describe the single-access evaluation:

temp=index, (index=temp+1,0) + (*temp=topupper(*temp));

The addition of the parenthesised expessions is an artifact introduced merely
to stress the fact that both `=' operators may be evaluated in parallel (the
second one still contains our red herring access-and-modification). This
rewritten version is strictly conforming: the assignment to `index' and the
evaluation of the argument to `toupper' no longer involve the same object. Of
course I'm not suggesting to use this rewrite in practice; it just illustrates
the essential point.

--

Douglas A. Gwyn

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
"Clive D.W. Feather" wrote:
> In:
> *x = y
> there are no sequence points restricting the relative order of the
> evaluations of x and y. Even where y involves an internal sequence
> point.

? If in x;y the side effects of x have to be completed before y
due to the s.p. at the ; then why in y=f(x) don't they have to due
to the s.p. at the ()? What is different about the two s.p.s?

I would hate to think that the side effects *inside* the function
call don't have to be flushed (due to the s.p. at function return)
before the evaluation of y in y=f(x) What is so different between
the s.p. at the function call and the s.p. inside the function??

Douglas A. Gwyn

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Marc van Leeuwen wrote:
> But in the example the (character or integer) value to be stored by the
> assignement operartor is not replacing the (pointer) value of `index'.

The object I had in mind was *index.

Marc van Leeuwen

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Dennis Ritchie <d...@bell-labs.com> writes:

> "Douglas A. Gwyn" wrote:
>
> > The spec says "... there is a sequence point before the actual call".
> > How do you get from evaluating the argument to using the result of
> > the function call without passing through at least one sequence point?
>

> In the *index = toupper(*index++) case, maybe by evaluating *index,

> a sufficient subexpression for generating the argument's value. Then stash
> the LHS index. Then call (sequence point, but the larger arg expression
> wasn't evaluated yet). Then store through the stashed version of
> the LHS, finally increment index.

I'm sorry, but this only confuses the issue further. Firstly the example was
different, with the post-increment in the LHS (the difference does not effect
presence of the undefined behaviour though). But more importantly, you are
suggesting an interpretation that strips all meaning from sequence points.
Unless I completely misunderstand your phrase, you are saying that although
entry to the call (of `toupper') involves a sequence point, the "larger arg
expression" (that must be `*index++') is left in it's "not yet fully
evaluated" state with pending side effects, until completing the call (and
the assignment). Isn't the whole point of sequence points that all side
effects of evaluations that have necessarily been commenced (as the evaluation
of `*index++' in this case) must be completed before proceeding? In this case
that means that if `toupper' is a function in whose body `index' is accessed,
then it must find the incremented value; in your scenario it would not. On the
other hand (to illustrate "necessarily commenced" above) any side effects of
evaluating the LHS (there aren't any in your example, but there was one in the
original one) need not be flushed upon entering `toupper', because that
evaluation need not have started to make the call possible.

The answer to Douglas' original question must be that on the path he mentioned
there is indeed always a sequence point (in fact at least 2: one on entering
and one on leaving the function call). But that does not help, since the
problem was not with storing the result of the function call, but with storing
(and accessing) the value of `index'.

Tony Brown

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Thanks to all who took time to contribute to this thread, your input is much
appreciated. Even after 20 years of C programming, it seems there is still
more to learn.

Regards to all
Tony Brown


Paul Eggert

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Michael Rubenstein <mik...@ix.netcom.com> writes:

>Sequence points are a partial, not a complete, ordering.

I agree with you, but when this subject came up earlier
at least one member of the committee disagreed:
he said that sequence points must be a total order,
and that the order for a particular execution is
defined by the implementation.

Unfortunately, the semantics of sequence points has never been clear.
The idea of sequence points was an invention of the committee, and not
one of the happier ones. The standard would be better off without the
idea of sequence points: there are better mechanisms for defining the
order of evaluation.

Paul Jarc

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:
> I would hate to think that the side effects *inside* the function
> call don't have to be flushed (due to the s.p. at function return)
> before the evaluation of y in y=f(x)

That sequence point must come before the assignment is done, but why
would it necessarily precede the evaluation of y? Order of evaluation
of operands is unspecified.


paul

Peter Seebach

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
In article <38BE1AFC...@null.net>,

Douglas A. Gwyn <DAG...@null.net> wrote:
>I agree, for that case, but I thought we were debating the reported
> *index++ = toupper(*index) // assumed to be a function call
>where a different line of argumentation would have to be found.

I don't see anything hard about making these all happen "at once"; you
evaluate 'index' on both sides before you make the call, and at some point
after you evaluate the LHS one (but possibly before you make the call) you
increment it. There's nothing between 'evaluate index to decide where to
store the result' and 'evaluate index to decide what to pass to toupper' that
requires a sequence point.

Peter Seebach

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
In article <38BE7A07...@null.net>,

Douglas A. Gwyn <DAG...@null.net> wrote:
>? If in x;y the side effects of x have to be completed before y
>due to the s.p. at the ; then why in y=f(x) don't they have to due
>to the s.p. at the ()? What is different about the two s.p.s?

You're allowed to evaluate the arguments of the function, cache them, and
come back to the actual call later.

>I would hate to think that the side effects *inside* the function
>call don't have to be flushed (due to the s.p. at function return)

>before the evaluation of y in y=f(x) What is so different between
>the s.p. at the function call and the s.p. inside the function??

Evaluation of 'y' is not all-or-nothing. Once again, you are allowed to cache
values for future use, and the promise that excess modifications will not occur
between sequence points means you're allowed to assume that nothing is being
changed "under your feet".

Clive D.W. Feather

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
In article <38BE7A07...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>> In:
>> *x = y
>> there are no sequence points restricting the relative order of the
>> evaluations of x and y. Even where y involves an internal sequence
>> point.
>
>? If in x;y the side effects of x have to be completed before y
>due to the s.p. at the ;

The sequence point is between the evaluation of x and that of y. In
diagrammatic form:

x --- ; --- y

>then why in y=f(x) don't they have to due
>to the s.p. at the ()? What is different about the two s.p.s?

The sequence point is only between the function arguments/name and the
call. The diagram is:

x -\
>- () -\
f -/ \
>- =
/
y ---------/

>I would hate to think that the side effects *inside* the function
>call don't have to be flushed (due to the s.p. at function return)
>before the evaluation of y in y=f(x)

Why not ? y could be evaluated before x. See above.

In the original example: *z++ = f (*z)
the diagram is:

z --- * -\
>- () -\
f -------/ \
>- =
/
/- * -------/
z --<
\- ++

[This diagram is rather informal. Annex S expressed it more formally.]

Dennis Yelle

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Paul Eggert wrote:
[...]

> Unfortunately, the semantics of sequence points has never been clear.
> The idea of sequence points was an invention of the committee, and not
> one of the happier ones. The standard would be better off without the
> idea of sequence points: there are better mechanisms for defining the
> order of evaluation.

Please tell me where to find the details of one (or more) of
these better mechanisms.

Thanks.

Dennis Yelle

--
Please play with my new Java toy:
http://www.fortunecity.com/roswell/barada/186/chaos/
(If you and your browser ever do that sort of thing.)

Larry Jones

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Douglas A. Gwyn (DAG...@null.net) wrote:
> Larry Jones wrote:
> > No, index is still being modified and used (other than to determine
> > the new value) with no intervening sequence point, so it's still
> > undefined behavior.
>
> The instance of "index" on the RHS is clearly being used only to
> determine the new value to be stored by the assignment operation.

> So I assume you're referring to the instance of "index" on the LHS.
> In which case, watch out that your argument doesn't also outlaw
> *x++ = 1, which I think we all agree should be usable in a strictly
> conforming program.

I understand what you're saying, but I can't think of any way to express
the intent more clearly in English than what we already have (we really
need Clive's proposed Annex S). Consider the following:

a[i++] = 1;
a[i++] = i;
a[i++] = f(i);

The first is clearly intended to be well defined, the second is clearly
intended to be undefined (it's an example in footnote 70 in C99), the
third is, I believe, equivalent to what we've been discussing. While
the "i" on the RHS is being used to determine the value to be stored by
the assignment, it is NOT being used to determine the value to be stored
in "i", only the "i" on the LHS is, so I believe the expression as a
whole violates the sequence point rules. Even if it isn't undefined,
it's certainly unreliable since there's no way to know whether the "i++"
on the LHS is evaluated before or after the "i" on the RHS. I'm not
sure what Annex S says about this expression, but I suspect it calls it
undefined, which I agree with.

Just for completeness sake, I'll go ahead and mention:

a[a[i]] = 1; // where a[i] == i

where it seems reasonably clear that the inner reference to a[i] most
definitely is NOT being used to determine the new value to be stored in
a[i] (rather, it's being used to determine where to store the value),
but it nonetheless seems like it *should* be well-defined since the
inner reference must be evaluated before the outer reference can be.
(And I believe that Annex S agrees.)

-Larry Jones

How am I supposed to learn surgery if I can't dissect anything? -- Calvin

Michael Rubenstein

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
On 2 Mar 2000 09:17:30 -0800, egg...@twinsun.com (Paul Eggert)
wrote:

>Michael Rubenstein <mik...@ix.netcom.com> writes:
>
>>Sequence points are a partial, not a complete, ordering.
>
>I agree with you, but when this subject came up earlier
>at least one member of the committee disagreed:
>he said that sequence points must be a total order,
>and that the order for a particular execution is
>defined by the implementation.

I know this is unfair since you're not the one making the claim,
but I'm very curious to here the argument for that position if
you can reproduce it. I just can't see it.

Paul Eggert

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
Dennis Yelle writes:

>Paul Eggert wrote:
>> The standard would be better off without the idea of sequence points:
>> there are better mechanisms for defining the order of evaluation.

>Please tell me where to find the details of one (or more) of
>these better mechanisms.

Well, for starters:

The Ada standard.
The ALGOL68 standard.
The Common Lisp standard.
The Fortran standard.
The PL/I standard.
The Scheme standard.

None of these standards are perfect, of course.
Nor do they specify languages with the same order-of-evaluation rules as C.
But all of them use definitional methods better than the one used in
the C Standard. The interminable disputes among C experts about order
of evaluation simply do not occur with these other standards.

If you're interested in C per se, I suggest Norrish's thesis:
http://www.cl.cam.ac.uk/users/mn200/PhD/
It uses methods far superior to those used in the current C standard.
It's better even than the non-normative appendix on order of evaluation
that was in early C9x drafts.

Norrish's thesis is not suitable for the next version of the standard
as-is, but it's the best available basis for a standard that I know of.

Paul Eggert

unread,
Mar 2, 2000, 3:00:00 AM3/2/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:

>Paul Eggert wrote:
>> The standard would be better off without the idea of sequence points:
>> there are better mechanisms for defining the order of evaluation.

>Maybe, but do they have the same result?

Yes, Standard C's order-of-evaluation rules do differ from those of
most other languages. However, many techniques used to define the
order of evaluation in other languages also work for C.

>C89 "sequence points" were, I think, an
>attempt at a compromise in order to guarantee *some*thing about
>interactions between different parts of a program in the face of
>aggressive optimization.

Unfortunately that compromise complicated matters so greatly that I
can't help wondering whether all the consequences were understood at
the time. Granted, it's easier to specify the order-of-evaluation
semantics of Fortran, which allows much more optimization than C does.
It's also easier to express the semantics of, say, Scheme, which
specifies order of evaluation more than C does (and thus forbids some
optimizations). But these simplicities did not arise by accident.
These standards are better written because their authors were more
realistic about what a standard can and cannot do.

Had the C Standard's compromisers written down exactly what they meant
in a formal or semi-formal notation, they would have realized what a
mess they were getting themselves (and us) into. But they didn't.
And the result, unfortunately, is a standard that is murky indeed.

Douglas A. Gwyn

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
Larry Jones wrote:
> (we really need Clive's proposed Annex S)

I agree with that, provided that we make sure we can agree with what
gets adopted. (Too bad there wasn't time to be fix up the previous
proposal and be sure we had gotten it right for C99.)

Douglas A. Gwyn

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
Paul Eggert wrote:
> The standard would be better off without the idea of sequence points:
> there are better mechanisms for defining the order of evaluation.

Maybe, but do they have the same result?

My preference, which is *not* what was adopted, is that the VM order
of operations is strictly determined by the parse tree (which should
be unique), and if an implementation can get the same effect using
short-cuts, that's great (the "as if" rule). I *think* that is what
the original intent of C was (perhaps Dennis could confirm this),
but over time many people pushed for optimization at the expense of
accurate VM execution. C89 "sequence points" were, I think, an


attempt at a compromise in order to guarantee *some*thing about
interactions between different parts of a program in the face of

aggressive optimization. It was awkward to express some aspects of
that compromise in English.

James Kuyper

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to

Perhaps a better, more easily understood compromise is possible, and if
so would certainly be desirable, but it should remain a compromise. If
there was only one permitted order of operations, then the optimizations
that could be achieved by rearranging the order would have to be done by
the programmer rather than by the compiler. This has two disadvantages:
firstly, modern compilers are much better at figuring out such
optimizations than programmers. Programmer time is much more valuable
than computer time nowadays. Secondly, the optimum order of execution
may be different on different implementations. The last thing we
overworked programmers need is a fresh temptation for #if'ing our code.

If you want precise control of the order of operations, you can usually
break complex expressions down into separate statements so simple that
there is only one permitted order, even under the current rules.
However, programmers who don't want to excersize that level of control
shouldn't have to pay a performance penalty for not doing something that
compilers typically do much better anyway.

Douglas A. Gwyn

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
James Kuyper wrote:
> ... modern compilers are much better at figuring out such
> optimizations than programmers.

My point was that the compiler could optimize to any degree
short of changing the semantics. In such a language,
*p++ = *p++ + 1;
could be given the meaning that so many naive programmers
seem to think it has, which could only improve reliability
and portability. If carried a step farther, order of
evaluation of operands would be specified in most cases, so
*p++ = *p++ + 1 - *p++;
would have a well-defined result. I don't think it does
anyone any good to allow compilers to optimize such stuff
with random order, because in such expressions one really
doesn't *want* the compiler to pick a random order; the
code only makes sense if the specific order the programmer
intended is what he actually gets. In "ordinary" cases like
*p++ = *q++ + 1;
so long as p and q aren't aliasing (something compilers
can determine most of the time), the compiler can optimize
using delayed writes, etc. because that wouldn't affect the
semantic outcome.

I repeat, the above is *not* how C is required to work,
but it is an *allowed* implementation, and I'd prefer it
to be a requirement, in any new procedural language if not
in some future version of C.

Geoff Keating

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:

> My preference, which is *not* what was adopted, is that the VM order
> of operations is strictly determined by the parse tree (which should
> be unique), and if an implementation can get the same effect using
> short-cuts, that's great (the "as if" rule). I *think* that is what
> the original intent of C was (perhaps Dennis could confirm this),
> but over time many people pushed for optimization at the expense of
> accurate VM execution.

...


I'd have to agree with this, up to a point.

There were a number of other posters that said things like

James Kuyper <kuy...@wizard.net> writes:
> If there was only one permitted order of operations, then the
> optimizations that could be achieved by rearranging the order would
> have to be done by the programmer rather than by the compiler.

I don't believe that there are many programmers who put multiple
side-effects to potentially-identical variables in their expressions
so that the compiler can reorder them.

For GCC, for instance, the front-end decides what order side effects
happen in at parse time in a way which was chosen for historical
reasons and has no relationship now to any optimisation.


However, I do have a warning about the feasibility of standardising
this: GCC regularly gets `bug reports' complaining that GCC orders
these operations in a different way to some other compiler's ordering,
and the other ordering is `more natural' or `what a programmer would
expect'. The entertaining part is when you compare several of these
reports; the `more natural' orderings are different, both between
individual bug reports and when compared to other orderings like the
one that is standardised in Java.

So I predict that whatever ordering is chosen for standardisation,
someone will complain about it, and there will be many unhappy
compiler writers who end up having to support two orderings :-(.

--
- Geoffrey Keating <geo...@cygnus.com>

Peter Seebach

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
In article <jm4sana...@envy.cygnus.com>,

Geoff Keating <geo...@envy.cygnus.com> wrote:
>So I predict that whatever ordering is chosen for standardisation,
>someone will complain about it, and there will be many unhappy
>compiler writers who end up having to support two orderings :-(.

This is, in fact, why I want *no* specified ordering, and want potentially
ambiguous statements to be undefined behavior.

I want people to say exactly what they mean, and spell it out.

(And yet, I use C. Weird, huh?)

Tom Payne

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
Larry Jones <scj...@thor.sdrc.com> wrote:

> Douglas A. Gwyn (DAG...@null.net) wrote:

>> Larry Jones wrote:
>> > No, index is still being modified and used (other than to determine
>> > the new value) with no intervening sequence point, so it's still
>> > undefined behavior.

>> The instance of "index" on the RHS is clearly being used only to
>> determine the new value to be stored by the assignment operation.
>> So I assume you're referring to the instance of "index" on the LHS.
>> In which case, watch out that your argument doesn't also outlaw
>> *x++ = 1, which I think we all agree should be usable in a strictly
>> conforming program.

> I understand what you're saying, but I can't think of any way to express

> the intent more clearly in English than what we already have (we really
> need Clive's proposed Annex S).

Perhaps some phrase along the following line:

Between two sequence points, computational activity can overlap in
time, and accessing an object while it is being modified yields a
possibly invalid value representation and, hence, undefined behavior.
Of necessity, however, write access to an object will not overlap any
read access on which the written value depends.

> Consider the following:

> a[i++] = 1;
> a[i++] = i;
> a[i++] = f(i);

> The first is clearly intended to be well defined, the second is clearly
> intended to be undefined (it's an example in footnote 70 in C99), the
> third is, I believe, equivalent to what we've been discussing. While
> the "i" on the RHS is being used to determine the value to be stored by
> the assignment, it is NOT being used to determine the value to be stored
> in "i", only the "i" on the LHS is, so I believe the expression as a
> whole violates the sequence point rules. Even if it isn't undefined,
> it's certainly unreliable since there's no way to know whether the "i++"
> on the LHS is evaluated before or after the "i" on the RHS. I'm not
> sure what Annex S says about this expression, but I suspect it calls it
> undefined, which I agree with.

Does the Standard imply an order relationship between any part of the
evaluation of the lvalue a[i++] on the LHS and the sequence points
associated with the function call f(i) on the RHS? My guess is that
the answer is "no," in which case the evaluation of i++ can precede
the call and overlap the evaluation of its argument, namely i.

Tom Payne

Paul Jarc

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
Tom Payne <t...@roam-thp2.cs.ucr.edu> writes:

> Larry Jones <scj...@thor.sdrc.com> wrote:
> > I understand what you're saying, but I can't think of any way to express
> > the intent more clearly in English than what we already have (we really
> > need Clive's proposed Annex S).
>
> Perhaps some phrase along the following line:
>
> Between two sequence points, computational activity can overlap in
> time, and accessing an object while it is being modified yields a
> possibly invalid value representation and, hence, undefined behavior.
> Of necessity, however, write access to an object will not overlap any
> read access on which the written value depends.

If you mean that to be equivalent to Annex S, it needs some tweaking:
for one, Annex S also guarantees that writes do not overlap any
computation used to determine where the value will be written to.
This seems like it ought to be obvious and not-needing-to-be-stated,
but Michael Norrish's model differs on this very point, IIRC.


paul

Paul Jarc

unread,
Mar 3, 2000, 3:00:00 AM3/3/00
to
Tom Payne <t...@roam-thp2.cs.ucr.edu> writes:

> Paul Jarc <p...@po.cwru.edu> wrote:
> > If you mean that to be equivalent to Annex S, it needs some tweaking:
> > for one, Annex S also guarantees that writes do not overlap any
> ^^^^^^^^^^^^^^^^^^^^^^^

> > computation used to determine where the value will be written to.
>
> ... as does physical reality. ;-)

Not quite. Going by Norrish's interpretation, in `a[a[i]]=n', if
a[i]==i, then a conforming implementation is allowed to detect this
condition and correspondingly emit a helpful diagnostic, crash the
program, wipe the hard disk, or recite an incantation to summon demons
from your nasal cavity. Annex S prohibits this. Physical reality
does not, but laziness does.


paul

Tom Payne

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
Paul Jarc <p...@po.cwru.edu> wrote:
> Tom Payne <t...@roam-thp2.cs.ucr.edu> writes:
>> Larry Jones <scj...@thor.sdrc.com> wrote:
>> > I understand what you're saying, but I can't think of any way to express
>> > the intent more clearly in English than what we already have (we really
>> > need Clive's proposed Annex S).
>>
>> Perhaps some phrase along the following line:
>>
>> Between two sequence points, computational activity can overlap in
>> time, and accessing an object while it is being modified yields a
>> possibly invalid value representation and, hence, undefined behavior.
>> Of necessity, however, write access to an object will not overlap any
>> read access on which the written value depends.

Thanks for pointing that out the following.

> If you mean that to be equivalent to Annex S, it needs some tweaking:
> for one, Annex S also guarantees that writes do not overlap any
^^^^^^^^^^^^^^^^^^^^^^^
> computation used to determine where the value will be written to.

... as does physical reality. ;-)

> This seems like it ought to be obvious and not-needing-to-be-stated,


> but Michael Norrish's model differs on this very point, IIRC.

This fact should be noted via a sentence that make it clear that this
fact is a consequence of reality rather than a dictate of the
Standard. (Which is what I intended with the words "Of necessity, ...")

Tom Payne


Douglas A. Gwyn

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
Peter Seebach wrote:
> This is, in fact, why I want *no* specified ordering, and want
> potentially ambiguous statements to be undefined behavior.

How can you possibly write a sequential program under such conditions?

Dennis Ritchie

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to

Paul Eggert wrote, answering Dennis Yelle:

> >Please tell me where to find the details of one (or more) of

> >these better mechanisms [than 'sequence points'].


>
> Well, for starters:
>
> The Ada standard.
> The ALGOL68 standard.
> The Common Lisp standard.
> The Fortran standard.
> The PL/I standard.
> The Scheme standard.
>
> None of these standards are perfect, of course.
> Nor do they specify languages with the same order-of-evaluation rules as C.
> But all of them use definitional methods better than the one used in
> the C Standard. The interminable disputes among C experts about order
> of evaluation simply do not occur with these other standards.

None of these languages are fully functional (meaning 'pure-value
semantics', not 'fully working') so underneath the surface
they face the same issues that C does about effects from
evaluation order. Does current Fortran, for example,
say anything about exactly what happens with things
like

a(f(i)) = f(i)

or
c = f(i) + f(i)

where f might change some global state, or

print f(i), f(i)

with whatever changes might be needed to make them syntactically OK?
Is it flat out illegal, for example, for f to produce I/O, and
if it does, what happens? Do the Fortran people invoke the
nasal demons? (Real question; I no longer have even the F77 standard).
Is is just that it's a bit less easy to be infected with Fortran
rhinitis?

C, with its several side-effect producing expression operators,
does push the issue more in your face, and sequence points are
an attempt to deal with this. It would have been good, as I and others
have pointed out, to deal with 'sequence points' in a way that was more
explicit in relating the larger lexical and syntactical structure
of programs with the location of sequence points, and in particular
finding the place to use the phrase "partial order".

As a separate amusement, approximately arguing on the opposite
side: one of the U Waterloo descendants of B (probably either Eh or Zed)
used a strictly left-to-right (in the parse tree) evaluation scheme.
They reported, if I recall correctly, about the same performance
as with code generation algorithms that gave the compiler a lot
of slack. But this was on older machines without OOO mechanisms
and without a sophisticated or aggressive compiler against which
to compare.

Robert Corbett

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
In article <38C08FA0...@bell-labs.com>,

The only syntactic fixup needed is to change the last statement to

print *, f(i), f(i)

Section 7.1.7 of the Fortran standard states

The evaluation of a function reference shall neither affect
nor be affected by the evaluation of any other entity within
the statement. If a function reference causes definition or
undefinition of an actual argument of the function, that
argument or any associated entities shall not appear
elsewhere in the same statement. However, execution of a
function reference in the logical expression in an IF
statement (8.1.2.4), the mask expression in a WHERE
statement (7.5.3.1), or the subscripts and strides in a FORALL
statement (7.5.4) is permitted to define variables in the
statement that is conditionally executed.

Thus, the three statements given above might or might not be standard
conforming, depending on what the function reference does. The
Fortran standard does not require the nonconformant cases to be
detected, and few implementations try to detect them.

>Is it flat out illegal, for example, for f to produce I/O, and
>if it does, what happens?

Section 9.7 of the Fortran standard states

A function reference shall not appear in an expression anywhere
in an input/output statement if such a reference causes another
input/output statement to be executed.

The standard misses one case. A STOP statement is not considered
an input/output statement. The standard does not say what the effect
of executing a STOP statement as a result of a function reference
within an input/output list might be. For example, the standard does
not say that

WRITE (*, *) 'F(X) =', F(X), 'F(Y) =', F(Y)

is not conformant if either F(X) or F(Y) causes a STOP statement to
be executed, but it does not say what the result should be either.

>Do the Fortran people invoke the
>nasal demons? (Real question; I no longer have even the F77 standard).

No, we start WW III.

Sincerely,
Bob Corbett

Nick Maclaren

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
In article <89qggn$aev$1...@engnews1.eng.sun.com>,

I think that is a fair summary :-)

I am only slightly familiar with most of those standards, but have seen
most of them. In my view, there are two main language areas where
the C standard encites nasal demons in a way that the others do not,
plus several more where the library does. The language ones are:

The fact that C permits almost arbitrary aliasing, both by
different pointers and different types.

The way that the language is specified, with considerably more
obfuscations, ambiguities and unspecified unspecified behaviour.

I do NOT believe that side-effects and sequence points are much of
a particular problem AS SUCH - they are only serious because of the
second point. There have been two proposals to sort them out, and
both have been merely definitions - neither implied any significant
changes to the language.


Regards,
Nick Maclaren,
University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QG, England.
Email: nm...@cam.ac.uk
Tel.: +44 1223 334761 Fax: +44 1223 334679

Francis Glassborow

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
In article <89pepm$lon$1...@pravda.ucr.edu>, Tom Payne <thp@roam-
thp2.cs.ucr.edu> writes

>Does the Standard imply an order relationship between any part of the
>evaluation of the lvalue a[i++] on the LHS and the sequence points
>associated with the function call f(i) on the RHS? My guess is that
>the answer is "no," in which case the evaluation of i++ can precede
>the call and overlap the evaluation of its argument, namely i.

My understanding is that C imposes a requirement for sequential
computation, but places no equivalent requirement on side effects. The
latter can be done in any order and can overlap or be dispatched to
parallel processors. The only requirement is that imposed by sequence
points. Note that I do not think that sequence points place any direct
requirements on computations only on the side effects that result from
such.

>

Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Peter S. Shenkin

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to

Robert Corbett <cor...@lupa.Sun.COM> wrote in message
news:89qggn$aev$1...@engnews1.eng.sun.com...

> In article <38C08FA0...@bell-labs.com>,
> Dennis Ritchie <d...@bell-labs.com> wrote:
> > ... Does current Fortran, for example,

In other words, the Fortran standard tells the user, "if you do these
things, you are in violation of the standard." This is good to know, but
it's scarcely helpful when the user does it accidentally. It's no more
useful, in practice, than telling the C programmer "you shouldn't do this."

Similarly with the aliasing of procedure arguments, when one or more of the
aliased arguments will be defined (i.e., assigned to) in or beneath the
procedure: if you do this, you're in violation, but if you do it
accidentally, it's pretty tough for the compiler or run-time system to tell
you you have done so. In other words, you will have to repent for your
sins, but you won't be told what they were.

The F77 standard was written as a directive telling the user what he may and
may not do, not as a directive telling the compiler writer what he must and
must not do. I don't think the F9x standards take the same attitude, but
the fact is that the usages described above are proscribed by directive, not
by language design.

BTW, F95 allows a procedure to be defined as PURE, meaning that it has no
side effects and performs no IO. If a function, it cannot alter its dummy
args; if a subroutine, it can. The procedure can't contain a STOP
statement and cannot have any SAVEd variables (like C's local statics),
either. This is a nice feature, IMO, since it allows certain optimizations
that would otherwise be impossible, particularly in parallel code.

Also, if f() is PURE, the conscientious programmer will know, without having
to examine the contents of f(), that "a= f(i) + f(i)" is OK. He might even
feel free to change this to "a = 2 * f(i)" without carefully examining the
contents of f(). And if f() has the PURE attribute, even an unconscientious
programmer will be scolded at compile time if his changes to f() compromise
its purity.

Finally, I believe that recursive IO is to be allowed in F2000.

-P.


Peter Seebach

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
In article <38C08C8C...@null.net>,

I mean I want no specified ordering in the cases we're discussing. I'm
quite happy to have statements follow each other in the order they're written.

But I do *not* want things like
push(pop() - pop());
to be "defined" either way, because either way might be surprising to someone;
I'd rather have the language clearly tell you not to do that.

Robert Corbett

unread,
Mar 4, 2000, 3:00:00 AM3/4/00
to
In article <89rk8f$cf$1...@nntp5.atl.mindspring.net>,

Peter S. Shenkin <she...@schrodinger.com> wrote:
>
>Robert Corbett <cor...@lupa.Sun.COM> wrote in message
>news:89qggn$aev$1...@engnews1.eng.sun.com...
>>
>In other words, the Fortran standard tells the user, "if you do these
>things, you are in violation of the standard." This is good to know, but
>it's scarcely helpful when the user does it accidentally. It's no more
>useful, in practice, than telling the C programmer "you shouldn't do this."

Yes, the C and Fortran standards are the same in this regard.

>Similarly with the aliasing of procedure arguments, when one or more of the
>aliased arguments will be defined (i.e., assigned to) in or beneath the
>procedure: if you do this, you're in violation, but if you do it
>accidentally, it's pretty tough for the compiler or run-time system to tell
>you you have done so. In other words, you will have to repent for your
>sins, but you won't be told what they were.
>
>The F77 standard was written as a directive telling the user what he may and
>may not do, not as a directive telling the compiler writer what he must and
>must not do. I don't think the F9x standards take the same attitude, but
>the fact is that the usages described above are proscribed by directive, not
>by language design.

I disagree with your characterization of the FORTRAN 77 standard. The
standard specifies the result a standard confoming processor must produce
given a standard conforming program. The only thing the C standard does
that the FORTRAN 77 does not is add some conditions where diagnostic
messages must be given. The Fortran 90/95 standards match the C
standard in this respect.

N.B. The following section is Fortran specific. It is not related to
the C standard. I include it here only because it is a response to a
part of a posting to this group that is related to language standards.
Any response to the following portion of this posting should not be
posted to this group.

>Finally, I believe that recursive I/O is to be allowed in F2000.

The last draft I downloaded allowed internal I/O to be done as a
result of a function reference in an I/O list. External I/O is
still forbidden, and for good reason. What sense would it make to
allow a CLOSE, BACKSPACE, or REWIND to be executed on a unit in
the middle of the execution of a READ or WRITE statement that
references that unit?

Sincerely,
Bob Corbett

Douglas A. Gwyn

unread,
Mar 5, 2000, 3:00:00 AM3/5/00
to
Peter Seebach wrote:
> But I do *not* want things like
> push(pop() - pop());
> to be "defined" either way, because either way might be surprising to
> someone; I'd rather have the language clearly tell you not to do that.

Leaving it unspecified or undefined doesn't help, either.
So for consistency you should want there to be a required diagnostic.

Nick Maclaren

unread,
Mar 5, 2000, 3:00:00 AM3/5/00
to
In article <89s614$cmr$1...@engnews1.eng.sun.com>,

Robert Corbett <cor...@lupa.Sun.COM> wrote:
>
>>Finally, I believe that recursive I/O is to be allowed in F2000.
>
>The last draft I downloaded allowed internal I/O to be done as a
>result of a function reference in an I/O list. External I/O is
>still forbidden, and for good reason. What sense would it make to
>allow a CLOSE, BACKSPACE, or REWIND to be executed on a unit in
>the middle of the execution of a READ or WRITE statement that
>references that unit?

There is no technical difficult in permitting recursive I/O, provided
that the units are different. The reason for Fortran prohibited it
is historical, but I still had the devil of a job persuading people
that it was obsolete in the early 1980s!

Tom Payne

unread,
Mar 5, 2000, 3:00:00 AM3/5/00
to
Clive D.W. Feather <cl...@on-the-train.demon.co.uk> wrote:

> In the original example: *z++ = f (*z)
> the diagram is:

> z --- * -\
> >- () -\
> f -------/ \
> >- =
> /
> /- * -------/
> z --<
> \- ++

> [This diagram is rather informal. Annex S expressed it more formally.]

So, if I understand correctly, the sequence points associated with the
RHS have no impact on the LHS. For instance, if z is volatile and
gets incremented before the call to f, its new value doesn't have be
in place during the call to f. Right?

Tom Payne

Tom Payne

unread,
Mar 5, 2000, 3:00:00 AM3/5/00
to
James Kuyper <kuy...@wizard.net> wrote:

> "Douglas A. Gwyn" wrote:

>> Paul Eggert wrote:

[...]

>> > The standard would be better off without the idea of sequence points:
>> > there are better mechanisms for defining the order of evaluation.

>> Maybe, but do they have the same result?
>>

>> My preference, which is *not* what was adopted, is that the VM order
>> of operations is strictly determined by the parse tree (which should
>> be unique), and if an implementation can get the same effect using
>> short-cuts, that's great (the "as if" rule). I *think* that is what
>> the original intent of C was (perhaps Dennis could confirm this),
>> but over time many people pushed for optimization at the expense of

>> accurate VM execution. C89 "sequence points" were, I think, an
>> attempt at a compromise in order to guarantee *some*thing about
>> interactions between different parts of a program in the face of
>> aggressive optimization. It was awkward to express some aspects of
>> that compromise in English.

> Perhaps a better, more easily understood compromise is possible, and if

> so would certainly be desirable, but it should remain a compromise. If


> there was only one permitted order of operations, then the optimizations
> that could be achieved by rearranging the order would have to be done by

> the programmer rather than by the compiler. This has two disadvantages:

> firstly, modern compilers are much better at figuring out such
> optimizations than programmers.

Elsewhere in this thread Dennis Ritchie wrote:

[...]


> one of the U Waterloo descendants of B (probably either Eh or Zed)
> used a strictly left-to-right (in the parse tree) evaluation scheme.
> They reported, if I recall correctly, about the same performance
> as with code generation algorithms that gave the compiler a lot
> of slack. But this was on older machines without OOO mechanisms
> and without a sophisticated or aggressive compiler against which
> to compare.


Requiring a strict order (modulo the as-if rule) would only slow down
bugs. Any program whose observable behavior would change under such a
requirement already contains a potential for unexpected behavior under
reasonable circumstances (e.g., recompilation). Per C89, clause 4:

A strictly conforming program ... shall not produce output dependent
on any unspecified, undefined, or implementation-defined behavior.

What the sequence-point compromise has done is to turn compiler bugs
into (potentially life-threatening) program bugs and compiler "features."

Tom Payne


Clive D.W. Feather

unread,
Mar 6, 2000, 3:00:00 AM3/6/00
to
In article <89pepm$lon$1...@pravda.ucr.edu>, Tom Payne <thp@roam-
thp2.cs.ucr.edu> writes
>> I understand what you're saying, but I can't think of any way to express
>> the intent more clearly in English than what we already have (we really
>> need Clive's proposed Annex S).
>
>Perhaps some phrase along the following line:
>
> Between two sequence points, computational activity can overlap in
> time, and accessing an object while it is being modified yields a
> possibly invalid value representation and, hence, undefined behavior.
> Of necessity, however, write access to an object will not overlap any
> read access on which the written value depends.

This runs into much the same problems as the original wording did. In
particular, what does "between two sequence points" actually mean ? I
don't think this wording is any better than previous attempts.

--
Clive D.W. Feather | Internet Expert | Work: <cl...@demon.net>
Tel: +44 20 8371 1138 | Demon Internet | Home: <cl...@davros.org>
Fax: +44 20 8371 1037 | Thus plc | Web: <http://www.davros.org>
Written on my laptop; please observe the Reply-To address

Clive D.W. Feather

unread,
Mar 6, 2000, 3:00:00 AM3/6/00
to
In article <89ueig$gc$1...@pravda.ucr.edu>, Tom Payne <thp@roam-
thp2.cs.ucr.edu> writes

>> In the original example: *z++ = f (*z)

>So, if I understand correctly, the sequence points associated with the


>RHS have no impact on the LHS.

That is my interpretation.

>For instance, if z is volatile and
>gets incremented before the call to f, its new value doesn't have be
>in place during the call to f. Right?

Ditto.

Douglas A. Gwyn

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
> >For instance, if z is volatile and
> >gets incremented before the call to f, its new value doesn't have be
> >in place during the call to f. Right?
"Clive D.W. Feather" wrote:
> Ditto. [That is my interpretation.]

I still want to know why that argument doesn't also apply to f;g
(where f and g have side effects). Is it that ; is not considered
an operator within an expression, and the sequence point rules
apply only within an expression? If so, why do we spec a sequence
point at the ;

ke...@hplb.hpl.hp.com

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
In article <89nh5i$7pt$1...@green.twinsun.com>,
egg...@twinsun.com (Paul Eggert) writes:
> If you're interested in C per se, I suggest Norrish's thesis:
> http://www.cl.cam.ac.uk/users/mn200/PhD/

I got:

Forbidden

The proxy's access control configuration denies access to the
requested object through this proxy.

Me or they?

--
Chris "`poxy server` expresses it nicely" Dollin
C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html

Paul Jarc

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
*z++=f(*z);

"Douglas A. Gwyn" <DAG...@null.net> writes:

> > >For instance, if z is volatile and
> > >gets incremented before the call to f, its new value doesn't have be
> > >in place during the call to f. Right?
> "Clive D.W. Feather" wrote:
> > Ditto. [That is my interpretation.]
>
> I still want to know why that argument doesn't also apply to f;g
> (where f and g have side effects).

Because the increment to z is not part of an argument to f. If it
were, then it would be known to have occurred by the time f is called
(assuming we didn't still have undefined behavior anyway). The side
effects of f's arguments are complete by the time f is called; other
side effects need not be complete, because order of evaluation of
operands (of `=', in this case) is unspecified, so the subexpressions
generating those side effects need not have been evaluated at all at
the time f is called.

> Is it that ; is not considered an operator within an expression, and
> the sequence point rules apply only within an expression?

`;' certainly isn't an operator, but the sequence point rules apply
wherever there are sequence points. But the above argument applies
only to operations (or arguments to one function call), because it
depends on unspecified order of evaluation. In the case of the
sequence point at the end of a full expression (e.g., at `;'), order
of evaluation of specified.


paul

Kevin D. Quitt

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
On Mon, 6 Mar 2000 18:39:19 +0000, "Clive D.W. Feather"
<cl...@on-the-train.demon.co.uk> wrote:


>In article <89ueig$gc$1...@pravda.ucr.edu>, Tom Payne <thp@roam-
>thp2.cs.ucr.edu> writes
>>> In the original example: *z++ = f (*z)
>
>>So, if I understand correctly, the sequence points associated with the
>>RHS have no impact on the LHS.
>
>That is my interpretation.
>

>>For instance, if z is volatile and
>>gets incremented before the call to f, its new value doesn't have be
>>in place during the call to f. Right?
>

>Ditto.

I remember asking why it would have been bad to have made the assignment
operator a sequence point and require rhs evaluation first. I don't
remember if any of the answers I got were really convincing. Is there
some reason this would be bad?

--
#include <standard.disclaimer>
_
Kevin D Quitt USA 91351-4454 96.37% of all statistics are made up
Per the FCA, this email address may not be added to any commercial mail list

Tom Payne

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
Kevin D. Quitt <KQu...@ieeinc.com> wrote:
> On Mon, 6 Mar 2000 18:39:19 +0000, "Clive D.W. Feather"
> <cl...@on-the-train.demon.co.uk> wrote:


>>In article <89ueig$gc$1...@pravda.ucr.edu>, Tom Payne <thp@roam-
>>thp2.cs.ucr.edu> writes
>>>> In the original example: *z++ = f (*z)
>>
>>>So, if I understand correctly, the sequence points associated with the
>>>RHS have no impact on the LHS.
>>
>>That is my interpretation.
>>
>>>For instance, if z is volatile and
>>>gets incremented before the call to f, its new value doesn't have be
>>>in place during the call to f. Right?
>>
>>Ditto.

> I remember asking why it would have been bad to have made the assignment
> operator a sequence point and require rhs evaluation first. I don't
> remember if any of the answers I got were really convincing. Is there
> some reason this would be bad?

It would make bugs run slower. ;-)

Tom Payne

Tom Payne

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
Clive D.W. Feather <cl...@on-the-train.demon.co.uk> wrote:
> In article <89pepm$lon$1...@pravda.ucr.edu>, Tom Payne <thp@roam-
> thp2.cs.ucr.edu> writes
[...]

>>Perhaps some phrase along the following line:
>>
>> Between two sequence points, computational activity can overlap in
>> time, and accessing an object while it is being modified yields a
>> possibly invalid value representation and, hence, undefined behavior.
>> Of necessity, however, write access to an object will not overlap any
>> read access on which the written value depends.

> This runs into much the same problems as the original wording did. In
> particular, what does "between two sequence points" actually mean ? I
> don't think this wording is any better than previous attempts.

I was trying for a more intuitive version of the C89 statement, and I
agree with you about the imprecision of "between".

It seems that sequence points are associated with operations
(occurrences of operators) which in turn are associated with nodes in
the syntax tree, which in turn imposes an order on those operations:
- children precede parents
- left-side descendants of a ;-node precede right-side descendants
- the condition of an if-node precedes the body
- etc.
The interval between two sequence points consists of all operations in
that are preceded by (the operation associated with) the first and
that precede (the operation associated with) the second. The
operations in a minimal interval form a directed acyclic graph (a.k.a,
partially ordered set). Whenever an operation in a minimal interval
accesses an object that is modified by an noncomparable operation in
that same minimal interval, the resulting behavior is undefined.

Right?

Tom Payne

Clive D.W. Feather

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
In article <38C47D76...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>>>For instance, if z is volatile and
>>>gets incremented before the call to f, its new value doesn't have be
>>>in place during the call to f. Right?

>I still want to know why that argument doesn't also apply to f;g


>(where f and g have side effects).

Because the sequence point applies to f and g, not to just
subexpressions of f and g. Look again at the diagrams I posted, or read
Annex S.

David R Tribble

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
"Clive D.W. Feather" wrote:
> ... or read Annex S.

Where can I, not being a member of the committee, obtain Annex S?
The latest draft I have is WG14/N869, 1999-01-18, which does not
contain Annex S (only going up to Annex J).

-- David R. Tribble, da...@tribble.com, http://david.tribble.com --

Paul Eggert

unread,
Mar 7, 2000, 3:00:00 AM3/7/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:

>I was wondering what the logic is for
>arguing that the side effects in g cannot precede the side
>effects in f, in the schematic construct f;g ....
>Given that logic, why does it not say the same thing about g=h(f)
>? It cannot be "there is a sequence point between f and g",
>because that is also true for g=h(f)

But there is no sequence point between f and g in g=h(f).
There is a sequence point between f and the invocation of h,
but that's not the same thing as saying there's a sequence point
between f and g.

Informally speaking (not that the standard is either clear or formal here :-),
g might be executed in parallel with f, or with h, or with both.

Similar logic applies to g=(f,h).

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
"Clive D.W. Feather" wrote:
> <DAG...@null.net> writes

> >I still want to know why that argument doesn't also apply to f;g
> >(where f and g have side effects).
> Because the sequence point applies to f and g, not to just
> subexpressions of f and g. ...

I don't think my question has been understood; probably my fault
for being too concise. I was wondering what the logic is for


arguing that the side effects in g cannot precede the side

effects in f, in the schematic construct f;g . (There *must* be
some such logic, because we all agree that that is the case.)


Given that logic, why does it not say the same thing about g=h(f)
? It cannot be "there is a sequence point between f and g",

because that is also true for g=h(f), which you all are arguing
does *not* guarantee that side effects in f are completed before
side effects in g.

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Paul Eggert wrote:
> But there is no sequence point between f and g in g=h(f).

Sure seems like there is. You cannot get from f to g without
crossing the evaluation of h, which means crossing the sequence
point between the evaluation of the arguments to h and the
call to h. My question would be clearer if we expressed the
parse tree in Polish notation instead of the strange mixture of
{pre-,suf-,in-)fix and ()-functional notation of C source code.

> g might be executed in parallel with f, or with h, or with both.

I'm still trying to see why the sequence point doesn't affect that.

Dik T. Winter

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
In article <38C62DC6...@null.net> "Douglas A. Gwyn" <DAG...@null.net> writes:
> Paul Eggert wrote:
> > But there is no sequence point between f and g in g=h(f).
>
> Sure seems like there is. You cannot get from f to g without
> crossing the evaluation of h, which means crossing the sequence
> point between the evaluation of the arguments to h and the
> call to h.

By this same reasoning there is a sequent point between f and g
in g = (f, h). The point here is that you do not need the
evaluation of 'h' in both cases to get at the lvalue of the
left-hand side.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

James Kuyper

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
"Douglas A. Gwyn" wrote:
...
> I don't think my question has been understood; probably my fault
> for being too concise. I was wondering what the logic is for
> arguing that the side effects in g cannot precede the side
> effects in f, in the schematic construct f;g . (There *must* be
> some such logic, because we all agree that that is the case.)
> Given that logic, why does it not say the same thing about g=h(f)
> ? It cannot be "there is a sequence point between f and g",
> because that is also true for g=h(f), which you all are arguing

Where? There's no sequence point separating the left and right hand
sides of an assignment operator. That's the single most common source of
confusion about sequence points.

We have the following constraints:
1. f must be evaluated before h() is, and there's a sequence point
separating the two.
2. g and h() must both be evaluated before '=' is evaluated.

That permits the following orderings:

f, point, h(), g, =
f, point, g, h(), =
f, g, point, h(), =
g, f, point, h(), =

In two of the four legal orderings, there is no sequence point
separating f and g.

For your example: "f;g", there is only one legal ordering, in that order
f is separated from g by a sequence point.

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
"Dik T. Winter" wrote:
> By this same reasoning there is a sequent point between f and g
> in g = (f, h).

Yes! But not between h and g.

> The point here is that you do not need the evaluation of 'h' in
> both cases to get at the lvalue of the left-hand side.

In a lengthy C program, I do not need the evaluation of any of the
early ;-separated statements in order to "get at" the lvalue of the
last assignment statement. That doesn't mean that their side
effects don't have to be already caught up before evaluating that
lvalue.

In g=(f,h) what if the evaluation of f affects the lvalue g? (g
could be *p where f modifies p.) How does that differ from f;g=h ?
Structurally these are practically identical, and there is a s.p.
after the evaluation of f in both cases.

Heinz Huber

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Hi!

Jumping in on the discussion.

"Douglas A. Gwyn" wrote:
>
[snip]


> I still want to know why that argument doesn't also apply to f;g

> (where f and g have side effects). Is it that ; is not considered


> an operator within an expression, and the sequence point rules

> apply only within an expression? If so, why do we spec a sequence
> point at the ;

Anybody correct me if I'm wrong (I'm sure you will;-):
AFAIK ; is no operator. It separates statements. Each statement must be
completed, before the next begins. Therefore, f and all it's side
effects have to be evaluated before g is evaluated.

Heinz

James Kuyper

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
"Douglas A. Gwyn" wrote:
>
> Paul Eggert wrote:
> > But there is no sequence point between f and g in g=h(f).
>
> Sure seems like there is. You cannot get from f to g without
> crossing the evaluation of h, which means crossing the sequence

Why not? There's nothing that requires evaluation of h() before
evaluation of g.

> point between the evaluation of the arguments to h and the

> call to h. My question would be clearer if we expressed the
> parse tree in Polish notation instead of the strange mixture of
> {pre-,suf-,in-)fix and ()-functional notation of C source code.

The h(f) and g nodes occur at the same level of the parse tree, both
being operands of '='; as such they can be evaluated in either order. In
one of those two orders, the evaluation of 'g' is not separated from the
evaluation of 'f' by the sequence point that separates the evaluation of
'f' from the evaluation of 'h'.

> > g might be executed in parallel with f, or with h, or with both.
>
> I'm still trying to see why the sequence point doesn't affect that.

Sequence points don't constrain the order of evaluation. They serve only
to constrain when side effects may occur, relative to the evaluation
order.
If a legal order puts no sequence points between two expressions that
modify the same object's stored value, the behavior is undefined.
However, that constrains legal programs, not the implementation's choice
in the order of evaluation.

Can you cite any text suggesting that sequence points do constrain the
evaluation order?

James Kuyper

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Heinz Huber wrote:
...

> AFAIK ; is no operator. It separates statements. Each statement must be
> completed, before the next begins. Therefore, f and all it's side
> effects have to be evaluated before g is evaluated.

The way the standard says that, is by saying that there's a sequence
point at the end of each statement.

Doug's point is that there is a sequence point separating 'f' from 'g'
in "f;g", and he believes that the sequence point separating 'f' from
'h' in "g=h(f)" also separates the 'f' from the 'g'. IMO it doesn't.

Mark Williams

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
In article <38C62DC6...@null.net>,

"Douglas A. Gwyn" <DAG...@null.net> wrote:
> Paul Eggert wrote:
> > But there is no sequence point between f and g in g=h(f).
>
> Sure seems like there is. You cannot get from f to g without
> crossing the evaluation of h, which means crossing the sequence
> point between the evaluation of the arguments to h and the
> call to h. My question would be clearer if we expressed the
> parse tree in Polish notation instead of the strange mixture of
> {pre-,suf-,in-)fix and ()-functional notation of C source code.

OK - lets do that... hmmm...
g f h <call> =

Yes! You're right, it does make it clearer - there's no sequence point
between f & g :-)

Or maybe you were thinking:
f h <call> g =

-------------
Mark Williams


Sent via Deja.com http://www.deja.com/
Before you buy.

Tom Payne

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Douglas A. Gwyn <DAG...@null.net> wrote:
> "Clive D.W. Feather" wrote:
>> <DAG...@null.net> writes
>> >I still want to know why that argument doesn't also apply to f;g
>> >(where f and g have side effects).
>> Because the sequence point applies to f and g, not to just
>> subexpressions of f and g. ...

> I don't think my question has been understood; probably my fault
> for being too concise. I was wondering what the logic is for
> arguing that the side effects in g cannot precede the side
> effects in f, in the schematic construct f;g . (There *must* be
> some such logic, because we all agree that that is the case.)

Because there is a sequence point attached to the ; enforcing everyone's
intuition about the semantics of sequential execution.

> Given that logic, why does it not say the same thing about g=h(f)
> ? It cannot be "there is a sequence point between f and g",
> because that is also true for g=h(f), which you all are arguing

> does *not* guarantee that side effects in f are completed before
> side effects in g.

Because, to allow for the generation of the most optimal code in the
buggy case where the order makes a difference, the Standard does not
specify order of evaluation of the LHS and RHS of an assignment. The
evaluation of g can be overlapped and interleaved in arbitrary ways
with the evaluation of h(f). Sigh!

Your earlier proposal to pick a definite order and enforce it
modulo the as-if rule was absolutely correct.

Tom Payne

Larry Jones

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Douglas A. Gwyn (DAG...@null.net) wrote:
> Paul Eggert wrote:
> > But there is no sequence point between f and g in g=h(f).
>
> Sure seems like there is. You cannot get from f to g without
> crossing the evaluation of h, which means crossing the sequence
> point between the evaluation of the arguments to h and the
> call to h. My question would be clearer if we expressed the
> parse tree in Polish notation instead of the strange mixture of
> {pre-,suf-,in-)fix and ()-functional notation of C source code.

Yes. Remember that there are no constaints on the order of evaluation
other than those explicitly stated by the standard and the implicit
assumption that all the operands must be evaluated before the operator
can be executed. That allows the following eight orderings:

f h <call> g <assign>
f h g <call> <assign>
f g h <call> <assign>
h f <call> g <assign>
h f g <call> <assign>
h g f <call> <assign>
g f h <call> <assign>
g h f <call> <assign>

Note that in six of the eight possible orderings there is no sequence
point between the evaluations of f and g.

I think the confusion is that sequence points are specified in terms of
the syntax, but they're really semantic entities that are more related
to the order of evaluation than to the lexicographic ordering.

-Larry Jones

Buddy, if you think I'm even going to BE here, you're crazy! -- Calvin

Paul Jarc

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:
> Paul Eggert wrote:
> > But there is no sequence point between f and g in g=h(f).
>
> Sure seems like there is. You cannot get from f to g without
> crossing the evaluation of h, which means crossing the sequence
> point between the evaluation of the arguments to h and the
> call to h.

Right - but you don't need to get from f to g at all. You need to get
from f to the assignment (through h), and you also need to get from g
to the assignment.


paul

Tom Payne

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Larry Jones <scj...@thor.sdrc.com> wrote:
> Douglas A. Gwyn (DAG...@null.net) wrote:
>> Paul Eggert wrote:
>> > But there is no sequence point between f and g in g=h(f).
>>
>> Sure seems like there is. You cannot get from f to g without
>> crossing the evaluation of h, which means crossing the sequence
>> point between the evaluation of the arguments to h and the
>> call to h. My question would be clearer if we expressed the
>> parse tree in Polish notation instead of the strange mixture of
>> {pre-,suf-,in-)fix and ()-functional notation of C source code.

> Yes. Remember that there are no constaints on the order of evaluation
> other than those explicitly stated by the standard and the implicit
> assumption that all the operands must be evaluated before the operator
> can be executed. That allows the following eight orderings:

> f h <call> g <assign>
> f h g <call> <assign>
> f g h <call> <assign>
> h f <call> g <assign>
> h f g <call> <assign>
> h g f <call> <assign>
> g f h <call> <assign>
> g h f <call> <assign>

> Note that in six of the eight possible orderings there is no sequence
> point between the evaluations of f and g.

As far as I can tell, sequence points are partially ordered and are
associated with the (static) code. The run-time (dynamic) order in
which sequence points occur happens to be a completion of that static
partial order but has no effect on whether or not the behavior is
undefined.

> I think the confusion is that sequence points are specified in terms of
> the syntax, but they're really semantic entities that are more related
> to the order of evaluation than to the lexicographic ordering.

The syntax tree should reflect the semantics of the language. If I
understand correctly, sequence points can be viewed as being attached
to:
A) function calls and
B) the root operations of
-- expression statements
-- left-most operands of &&, ||, ?, if-statements, while-statements
do-statements, and switch-statements
-- operands of return statements
-- the control operands of for-statements.
By the time an operation associated with a sequence point has occurred,
the side effects of if its (direct and indirect) operands must have been
completed (modulo the as-if rule).

Tom Payne


Dave Hansen

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
On Wed, 08 Mar 2000 11:10:45 GMT, Douglas A. Gwyn <DAG...@null.net> wrote:
[...]

>In g=(f,h) what if the evaluation of f affects the lvalue g? (g
>could be *p where f modifies p.) How does that differ from f;g=h ?

In f;g=h the side effects of f *must* be complete before g or h. The side
effects of g relative to h are undefined.

In g=(f,h) the side effects of f must be complete before h. The side
effects of f relative to g and h relative to g are undefined.

If the side effects of f affects the lvalue g, f;g=h guarantees those side
effects are complete before the evaluation of the lvalue g occurs, but
g=(f,h) does not have that guarantee.

>Structurally these are practically identical, and there is a s.p.
>after the evaluation of f in both cases.

Yes, but in g=(f,h) there is no sequence point between f and g.

That's my understanding of it anyway. I hope there's wording in the
standard to support it...

Regards,

--
-=Dave
--
Just my (10-010) cents.
I can barely speak for myself, so I certainly can't speak for B-Tree.
Change is inevitable. Progress is not.

Paul Jarc

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Tom Payne <t...@roam-thp2.cs.ucr.edu> writes:
> The syntax tree should reflect the semantics of the language. If I
> understand correctly, sequence points can be viewed as being attached
> to:
> A) function calls and
> B) the root operations of
> -- expression statements
> -- left-most operands of &&, ||, ?, if-statements, while-statements
> do-statements, and switch-statements
> -- operands of return statements
> -- the control operands of for-statements.

To be precise, if-, while-, do-, and switch-statements aren't
operations with operands; they're statements with controlling
expressions. These expressions are treated exactly the same way as
expression-statement expressions, return-statement expressions, and
the controlling expressions of for-statements: they are all full
expressions (i.e., expressions that are not subexpressions of other
expressions). Having collected things this way, we can (and the
standard does) say simply that there is a sequence point at the end of
each full expression.


paul

Paul Jarc

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:
> "Dik T. Winter" wrote:
> > By this same reasoning there is a sequent point between f and g
> > in g = (f, h).
>
> Yes! But not between h and g.

But the sequence point after f *isn't* between f and g, either. It's
between f and h, and there is the logical consequence that it must
precede the assignment itself, but *not* that it must precede the
evaluation of the LHS.

> In g=(f,h) what if the evaluation of f affects the lvalue g?

Undefined behavior. This, I think, is the ordering you have in mind:
eval f, comma's sequence point, eval h, eval g, assign h's value to g
But can you refute that the standard also allows (among others) these
orderings?
eval g, eval f, comma's sequence point, eval h, assign h's value to g
eval f, eval g, comma's sequence point, eval h, assign h's value to g
I say that you cannot, *because the standard does not specify the
order of evaluation of ='s operands*. That's the key. And these
orderings show no sequence point between the LHS's access of g and f's
modification of g; thus, we get undefined behavior.

> How does that differ from f;g=h ? Structurally these are


> practically identical, and there is a s.p. after the evaluation of
> f in both cases.

The sequence point follow f in both cases, but in this case it also
must precede the evaluation of g. In the previous case, that
condition need not hold.


paul

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Dave Hansen wrote:
> In g=(f,h) the side effects of f must be complete before h. The
> side effects of f relative to g and h relative to g are undefined.

I *know* that is how everybody wants to interpret it, but what is
the argument (that differs for f;g=h)? Saying that it must be so
isn't an argument.

> Yes, but in g=(f,h) there is no sequence point between f and g.

Not *immediately* between them, but somewhere between them:
The sequence point occurs between the evaluation of f and the
(somewhat later) evaluation of g in the expression's parse tree;
you can't walk up the parse tree (with sequence points inserted)
starting somewhere in f and reach g without crossing the
sequence point introduced in the comma evaluation.

Over the years I have become much more sympathetic to the idea
that programming languages need formal semantic specifications..
Unfortunately, C intentionally allows a lot of semantic latitude,
this idea of out-of-order evaluation being perhaps the worst part.

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Paul Jarc wrote:
> > g=(f,h)

> eval g, eval f, comma's sequence point, eval h, assign h's value to g
> > How does that differ from f;g=h ?
> The sequence point follow f in both cases, but in this case it also
> must precede the evaluation of g.

I *know* you want it that way, but what is the argument that for
f;g=h it cannot be evaluated as: eval g, eval f, semicolon's
sequence point, eval h, assign h's value to g ? Just as in g=(f,h) .
What is the difference (other than that that is what people want)?

That is why I said earlier that we want to watch out what argument
is accepted for this business. The argument I would prefer keeps
g from being evaluated before f in both cases, except as an
optimization when it doesn't affect the outcome.

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
James Kuyper wrote:
> Sequence points don't constrain the order of evaluation. They serve
> only to constrain when side effects may occur, relative to the
> evaluation order.

Finally, something that looks like a possible answer.

I suppose the reason that in f;g;h the side effects of f have to
temporally precede those of g and h, rather than the other way
around (which is allowed insofar as s.p.s are concerned if the
order of evaluation is unspecified) *solely* because the semantic
specification of ; says that there is a particular temporal order.
That means that in other contexts temporal order of side effects
(induced by a s.p. between two subsets of side effects) is seldom
specified. Presumably for the , operator the temporal order of
side effects is also specified (LHS before RHS), not just the
existence of a s.p. at the comma, which wouldn't accomplish that.
Kind of scary.

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Larry Jones wrote:
> I think the confusion is that sequence points are specified in terms of
> the syntax, but they're really semantic entities that are more related
> to the order of evaluation than to the lexicographic ordering.

I've just posted a response to James Kuyper's previous posting,
in which I summarize what seems to be the real issue. I *was*
tying s.p.s to the syntax, not the lexicographic ordering, but
it seems now to boil down to the fact that s.p.s do not
determine order of execution either. Only semantic specification
of the various operators (e.g. , and ;) induces any order of
execution.

Dave Hansen

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to

Now I'm confused. I thought sequence points were defined in terms of side
effects. In fact, paragraph 2 of 5.1.2.3 of N869 says

#V+
Accessing a volatile object, modifying an object, modifying a file, or
calling a function that does any of those operations are all side
effects,10) which are changes in the state of the execution environment.
Evaluation of an expression may produce side effects. At certain specified
points in the execution sequence called sequence points, all side effects
of previous evaluations shall be complete and no side effects of subsequent
evaluations shall have taken place. (A summary of the sequence points is
given in annex C.)
#V-

What is ``the semantic specification of ;'' and how does it define a
``particular temporal order'' independent of sequence points? Why wouldn't
the existence of a sequence point at the comma specify the temporal order of
the side effects of its operands?

>Kind of scary.

If true, I'd have to agree.

Regards,

Douglas A. Gwyn

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Dave Hansen wrote:
> Now I'm confused. I thought sequence points were defined in terms
> of side effects.

Yes.

> Evaluation of an expression may produce side effects. At certain specified
> points in the execution sequence called sequence points, all side effects
> of previous evaluations shall be complete and no side effects of subsequent
> evaluations shall have taken place.

That raises the question of what "the execution sequence" *is*.
My latest-posted theory is that the (temporal) execution sequence
is specified solely by semantics, not by the parse tree (grammar).

> What is ``the semantic specification of ;'' and how does it define
> a ``particular temporal order'' independent of sequence points?

Essentially, ; occurs at the end of an expression statement, and
6.6 Statements (1990) says "except as indicated, statements are
executed in sequence". The spec for ; itself says that statement
is executed by executing its expression (solely) for side effects.
That connects the side effects with the execution order for ;.

> Why wouldn't the existence of a sequence point at the comma
> specify the temporal order of the side effects of its operands?

I think it does; the (1990) spec says "the left operand ... is
evaluated ... *Then* the right operand is evaluated; ..." (My
emphasis.) "Then" is a temporal ordering.

If you wonder why this doesn't apply for ordering of the
evaluation of operands for = or + etc., that's because they
don't contain time-sequencing words in their semantic specs.

> >Kind of scary.
> If true, I'd have to agree.

I hope that it's still kind of scary..

Paul Jarc

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
"Douglas A. Gwyn" <DAG...@null.net> writes:
> Paul Jarc wrote:
> > > g=(f,h)
> > eval g, eval f, comma's sequence point, eval h, assign h's value to g
> > > How does that differ from f;g=h ?
> > The sequence point follow f in both cases, but in this case it also
> > must precede the evaluation of g.
>
> I *know* you want it that way, but what is the argument that for
> f;g=h it cannot be evaluated as: eval g, eval f, semicolon's
> sequence point, eval h, assign h's value to g ?

"At certain specified points in the execution sequence called sequence


points, all side effects of previous evaluations shall be complete and
no side effects of subsequent evaluations shall have taken place."

Are you claiming that the evaluation of g is a "previous evaluation",
or is not a "subsequent evaluation" relative to the sequence point at
the end of the full expression `f'?

> Just as in g=(f,h) . What is the difference (other than that that
> is what people want)?

As I've said repeatedly, the standard requires that in `f;g=h', g be
evaluated after f's sequence point. If you want chapter and verse,
look at 6.8p2, 6.8p4, and 6.8.3p2. (I'm using n869 numbering.) There
is no similar wording to make the analogous requirement for cases like
`g=(f,h)'.

> The argument I would prefer keeps g from being evaluated before f in
> both cases, except as an optimization when it doesn't affect the
> outcome.

No such argument has been given, and I don't see how such could be
based on the standard.


paul

Tom Payne

unread,
Mar 8, 2000, 3:00:00 AM3/8/00
to
Douglas A. Gwyn <DAG...@null.net> wrote:
> Paul Jarc wrote:
>> > g=(f,h)
>> eval g, eval f, comma's sequence point, eval h, assign h's value to g
>> > How does that differ from f;g=h ?
>> The sequence point follow f in both cases, but in this case it also
>> must precede the evaluation of g.

> I *know* you want it that way, but what is the argument that for
> f;g=h it cannot be evaluated as: eval g, eval f, semicolon's

> sequence point, eval h, assign h's value to g ? Just as in g=(f,h) .


> What is the difference (other than that that is what people want)?

> That is why I said earlier that we want to watch out what argument


> is accepted for this business.

We have to distinguish between arguments about what the Standard says
and what the Standard should say.

> The argument I would prefer keeps g from being evaluated before f in
> both cases,

In other words, you think that the Standard should specify
right-to-left evaluation for assignments. I don't really care which
order it specifies, but it should specify one or the other.

> except as an optimization when it doesn't affect the outcome.

Under the current standard, if order of evaluation affects outcome the
program is non-conforming. However, if the Standard specified a
particular order, those programs would come into conformance and
generate portably predictable behavior (for a change) --- but they
might run a bit slower. AFIK, the performance of conforming programs
would remain unchanged.

Tom Payne

Francis Glassborow

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
In article <38C6D638...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>> Yes, but in g=(f,h) there is no sequence point between f and g.
>
>Not *immediately* between them, but somewhere between them:

If you believe what you see but what if:

#define g (*x)
#define f (x=&j)
int i;
int j;
int * x = &i;
int h=1;
int main(){
g=(f,h);
// now what are the values of i and j?
}


Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Marc van Leeuwen

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
Kevin D. Quitt <KQu...@IEEInc.com> writes:
> I remember asking why it would have been bad to have made the assignment
> operator a sequence point and require rhs evaluation first. I don't
> remember if any of the answers I got were really convincing. Is there
> some reason this would be bad?

It would make certain optimisations more difficult, because the compiler would
have to prove very difficult things to justify them. Consider for instance

a[f(i)]=1-a[f(i)];

With the current standard, the compiler may IMHO decide that the identical
subexpressions f(i) need only be evaluated once, and the resulting index can
be used twice. If the call `f(i)' produces no side effects, then the statement
is conforming and the optimisation correct by the "as if" rule. If the call
does do nasty things (pops the stack or some such) then the behaviour is
undefined, and the optimisation is just as justified as any other action would
be. However, putting a sequence point between evaluation of RHS and LHS would
exclude undefined behaviour here, and force the compiler to generate two
successive calls of `f', unless it can prove, by inspection of the body of
`f', that a single call suffices by the "as if" rule (this is unlikely).

Note that as it is, justification of the optimisation without looking into `f'
still requires showing that ANY non-local side effect in the call makes
behaviour undefined. I believe it does, although the language of the standard
is of course not very helpful. Basically the two calls could be done
synchronously in parallel (with two sets of local variables) and if any
non-local object is modified (in both executions) then the two modifications
would lack a separating sequence point, ergo undefined behaviour. This
illustrates that optimisers really need undefined behaviour in a strong sense,
and that the sequence point parlance is frightfully inadequate to give it to
them. Just think what on earth the "previous and next sequence point" in our
magic incantation would have to be in this situation. Not to mention the hours
of discussions among people with different interpretations this could
generate. Anybody who claims that (while either of the two calls may be done
first) in the abstract machine the first call must be run to completion before
the second on is started (because of sequence points at entry and exit, for
instance), would be led to conclude that certain side effects (like printing a
fixed string to `stdout') would _not_ lead to undefined behaviour, and that
the optimisation is therefore to be rejected in general.

Personally I think (based on the spirit rather than the letter of the
standard) the optimisation is to be allowed, and that it would hurt no valid
program.

--
Marc van Leeuwen
Universite de Poitiers
http://wwwmathlabo.univ-poitiers.fr/~maavl/

Michael Norrish

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
Paul Jarc <p...@po.cwru.edu> writes:

> Tom Payne <t...@roam-thp2.cs.ucr.edu> writes:
> > Paul Jarc <p...@po.cwru.edu> wrote:
> > > If you mean that to be equivalent to Annex S, it needs some tweaking:
> > > for one, Annex S also guarantees that writes do not overlap any
> > ^^^^^^^^^^^^^^^^^^^^^^^
> > > computation used to determine where the value will be written to.
> >
> > ... as does physical reality. ;-)

> Not quite. Going by Norrish's interpretation, in `a[a[i]]=n', if
> a[i]==i, then a conforming implementation is allowed to detect this
> condition and correspondingly emit a helpful diagnostic, crash the
> program, wipe the hard disk, or recite an incantation to summon demons
> from your nasal cavity. Annex S prohibits this. Physical reality
> does not, but laziness does.

Paul is right. My interpretation would detect this usage and call it
undefined, but I must say that it makes the model considerably more
complicated. If I'd allowed myself Clive's latitude the formalisation
would have a deal simpler.

I'd be quite happy to see the wording change appropriately, and Annex
S adopted (at least as a stop-gap before the language standard is
completely rewritten to use a formal operational semantics :-)

Michael.


Clive D.W. Feather

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
In article <38C59A46...@tribble.com>, David R Tribble
<da...@tribble.com> writes
>Where can I, not being a member of the committee, obtain Annex S?

http://www.davros.org/c/wg14n822.txt but I am working on a new draft.
And despite the name, it isn't a formal annex of the Standard.

--
Clive D.W. Feather | Internet Expert | Work: <cl...@demon.net>
Tel: +44 20 8371 1138 | Demon Internet | Home: <cl...@davros.org>
Fax: +44 20 8371 1037 | Thus plc | Web: <http://www.davros.org>
Written on my laptop; please observe the Reply-To address

Clive D.W. Feather

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
In article <38C5C9BF...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>I don't think my question has been understood; probably my fault
>for being too concise. I was wondering what the logic is for
>arguing that the side effects in g cannot precede the side
>effects in f, in the schematic construct f;g . (There *must* be
>some such logic, because we all agree that that is the case.)

There is a sequence point at the end of the full expression f. Looking
at the parse tree, it is clear that that sequence point comes after f
(and everything in it) but before g (and everything in *it*).

>Given that logic, why does it not say the same thing about g=h(f)
>? It cannot be "there is a sequence point between f and g",
>because that is also true for g=h(f),

It isn't true. Look at the parse tree, which is very roughly:

=
/ \
g ()
/ \
h f

The sequence point is between h and f on the one side, and the call on
the other side. It is only on the right side of the branch from =, and
therefore unordered with respect to the left branch.

Clive D.W. Feather

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
In article <38C6D638...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>> Yes, but in g=(f,h) there is no sequence point between f and g.
>
>Not *immediately* between them, but somewhere between them:
>The sequence point occurs between the evaluation of f and the
>(somewhat later) evaluation of g in the expression's parse tree;

Here's your error. Who says that g is later in the parse tree than f ?
In other words, if we use reverse Polish notation the way you suggested
elsewhere, it could be:

g f h , =

rather than the

f h , g =

you seem to be assuming.

>you can't walk up the parse tree (with sequence points inserted)
>starting somewhere in f and reach g without crossing the
>sequence point introduced in the comma evaluation.

It's not clear to me that that is the correct definition. Why do I need
to "walk up the parse tree" ?

Clive D.W. Feather

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
In article <38C6DB17...@null.net>, Douglas A. Gwyn
<DAG...@null.net> writes

>I suppose the reason that in f;g;h the side effects of f have to
>temporally precede those of g and h, rather than the other way
>around (which is allowed insofar as s.p.s are concerned if the
>order of evaluation is unspecified) *solely* because the semantic
>specification of ; says that there is a particular temporal order.
>That means that in other contexts temporal order of side effects
>(induced by a s.p. between two subsets of side effects) is seldom
>specified. Presumably for the , operator the temporal order of
>side effects is also specified (LHS before RHS), not just the
>existence of a s.p. at the comma, which wouldn't accomplish that.

By George, he's got it !

Tom Payne

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
Douglas A. Gwyn <DAG...@null.net> wrote:
> Dave Hansen wrote:
>> In g=(f,h) the side effects of f must be complete before h. The
>> side effects of f relative to g and h relative to g are undefined.

> I *know* that is how everybody wants to interpret it, but what is
> the argument (that differs for f;g=h)? Saying that it must be so
> isn't an argument.

>> Yes, but in g=(f,h) there is no sequence point between f and g.

> Not *immediately* between them, but somewhere between them:
> The sequence point occurs between the evaluation of f and the
> (somewhat later) evaluation of g in the expression's parse tree;

> you can't walk up the parse tree (with sequence points inserted)
> starting somewhere in f and reach g without crossing the
> sequence point introduced in the comma evaluation.

You can walk UP the parse tree starting somewhere in f and reach g.
Period. Amen. The link from = to f goes down the tree.

Tom Payne

ke...@hplb.hpl.hp.com

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
In article <87r9dk9...@young.sp2mi.univ-poitiers.fr>,

Marc van Leeuwen <ma...@mathlabo.univ-poitiers.fr> writes:
> Kevin D. Quitt <KQu...@IEEInc.com> writes:
>> I remember asking why it would have been bad to have made the assignment
>> operator a sequence point and require rhs evaluation first. I don't
>> remember if any of the answers I got were really convincing. Is there
>> some reason this would be bad?
>
> It would make certain optimisations more difficult, because the compiler would
> have to prove very difficult things to justify them. Consider for instance
>
> a[f(i)]=1-a[f(i)];
>
> With the current standard, the compiler may IMHO decide that the identical
> subexpressions f(i) need only be evaluated once, and the resulting index can
> be used twice.

Are you sure about this? I would be gobsmacked if it were true. I write
two function calls, I *expect* two function calls. C being an aggressively
imperative language, I can't see that an optimiser is entitled to assume
that syntactically equal implies value-equal.

Myself, I'd favour explicit sequencing rules, and an aggressive application
of the as-if rule, but for C it's surely far too late.

--
Chris "strongly ordered" Dollin
C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html

Tom Payne

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to
Marc van Leeuwen <ma...@mathlabo.univ-poitiers.fr> wrote:
> Kevin D. Quitt <KQu...@IEEInc.com> writes:
>> I remember asking why it would have been bad to have made the assignment
>> operator a sequence point and require rhs evaluation first. I don't
>> remember if any of the answers I got were really convincing. Is there
>> some reason this would be bad?

> It would make certain optimisations more difficult, because the compiler would
> have to prove very difficult things to justify them. Consider for instance

> a[f(i)]=1-a[f(i)];

> With the current standard, the compiler may IMHO decide that the identical
> subexpressions f(i) need only be evaluated once, and the resulting index can

> be used twice. If the call `f(i)' produces no side effects, then the statement
> is conforming and the optimisation correct by the "as if" rule. If the call
> does do nasty things (pops the stack or some such) then the behaviour is
> undefined, and the optimisation is just as justified as any other action would
> be. However, putting a sequence point between evaluation of RHS and LHS would
> exclude undefined behaviour here, and force the compiler to generate two
> successive calls of `f', unless it can prove, by inspection of the body of
> `f', that a single call suffices by the "as if" rule (this is unlikely).

[...]


> This illustrates that optimisers really need undefined behaviour in a strong
> sense

[...]

Is there experimental evidence of significant speedup to offset
the confusion, astonishment, and bugs that this permission to optimize
introduces? How much slower would SpecInt run if we required say
left-to-right evaluation (modulo the as-if rule) in all cases where
the standard doesn't specify evaluation order? At a 1.5 year doubling
time for hardware speed, even a 10% speedup would be overcome by
hardware in a couple of months.

Tom Payne


Nick Maclaren

unread,
Mar 9, 2000, 3:00:00 AM3/9/00
to

In article <8a8gen$do5$1...@pravda.ucr.edu>, Tom Payne <t...@roam-thp2.cs.ucr.edu> writes:
|>
|> Is there experimental evidence of significant speedup to offset
|> the confusion, astonishment, and bugs that this permission to optimize
|> introduces? How much slower would SpecInt run if we required say
|> left-to-right evaluation (modulo the as-if rule) in all cases where
|> the standard doesn't specify evaluation order? At a 1.5 year doubling
|> time for hardware speed, even a 10% speedup would be overcome by
|> hardware in a couple of months.

Yes, in some codes. It is known as common expression elimination.
It is going to be even more important in C99, with the IEEE 754
rules.

The actual rate of speedup is most definitely not 50% per annum,
but more like 25%. 50% is the peak CPU speed, not the application
speed, and the memory speedup of 15% is typically more important
than the raw CPU speed.


Regards,
Nick Maclaren,
University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QG, England.
Email: nm...@cam.ac.uk
Tel.: +44 1223 334761 Fax: +44 1223 334679

It is loading more messages.
0 new messages