order of evaluation question 
Author Message
 order of evaluation question

#include <stdio.h>
int main(){
    double x, t;
    x = (t=2.0, t) + (t=3.0, t);
    printf("x = %f\n", x);
    return 0;

Quote:
}

Innocent as I am, I expected to see 5 here, but
I get 6 or 4 depending on the compiler. Is this a
case of some "for hard-core c programmers only"
precedence rules?

--
Erwin Kalvelagen
GAMS Development Corp.
1217 Potomac St. NW
Washington DC 20007
phone: (202) 342 0180
fax: (202) 342 0181

--



Sun, 07 Jul 2002 03:00:00 GMT  
 order of evaluation question

Quote:
Erwin Kalvelagen writes:
>     x = (t=2.0, t) + (t=3.0, t);

This causes undefined behavior.

Quote:
> Innocent as I am, I expected to see 5 here, but
> I get 6 or 4 depending on the compiler. Is this a
> case of some "for hard-core c programmers only"
> precedence rules?

Modifying the same variable twice in the same expression usually
causes undefined behavior.  This includes modifications using
operators like -- and ++ and += and -=, as well as the plain
assignment =.  "Hard-core C programmers" will know that there are
some cases where it's permissible to do it (due to sequence points),
but innocents would do best to avoid trying it.  Even among those
who know when it's legal would do best to avoid it, in most cases,
on the grounds that it tends to make your code incomprehensible.

And that is all you really need to know, but if you really want
the nitty-gritty, read on.

If the expression (t=2.0, t) was taken alone, the assignment
would be guaranteed to be completed before the right-hand t
was evaluated, because the comma operator creates a sequence
point.  So the value of the expression would be t.  And, of
course, similarly for the other subexpression.

But the + operator does not cause a sequence point; its operands
and their subexpressions can be evaluated in any order, except
as constrained by whatever operators that they contain.  In par-
ticular, evaluation of the two operands of + can be interleaved.

This means that your compiler can execute t=2.0 first, then t=3.0,
then go back and evaluate the t after t=2.0, then the other t.
That's how you get x = 6.  Similarly, if t=3.0 and t=2.0 are exe-
cuted in that order before anything else happens, you get x = 4.

Now you might think that the comma operator would protect you from
this, but it doesn't.  All that it cares about is making sure that
the t=2.0 happens *before* the t that comes after the comma; it
need not be *immediately* before.

Or you might think that the parentheses would protect you.  Wrong
again.  Parentheses in C expressions have a syntactic role only.
That is, they tell the compiler which subexpressions are operands
of which operator (and of course they have other syntactic jobs,
such as identifying function calls); but they *do not affect order
of evaluation*.

At this point you might think that you now understand that x must
be 4, 5, or 6, but even this is not guaranteed.  The behavior is
actually undefined; as far as the standard is concerned, x could
be -0.00031416, or your program could abort.  Why?  Because there's
a specific rule in the standard against modifying the same variable
twice without a sequence point intervening; if you do, the standard
says the behavior is undefined.

So if the subexpressions t=2.0 and t=3.0 are evaluated first (in
either order), then the two sequence points caused by the comma
operators can come after that, one after the other.  They come too
late to occur between the two subexpressions, and the rule applies.

See also questions 3.1 through 3.9 in the FAQ list.

And if your head is now spinning: just forget all this detail and
go back to the first paragraph.  Don't write code like this in
the first place, and you won't have a problem.

(Posted and emailed.)
--
Mark Brader   |  "I always pass on good advice.  It's the only thing
Toronto       |   to do with it.  It is never any use to oneself."

My text in this article is in the public domain.
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question

wrote in comp.lang.c.moderated:

Quote:

> #include <stdio.h>
> int main(){
>     double x, t;
>     x = (t=2.0, t) + (t=3.0, t);
>     printf("x = %f\n", x);
>     return 0;
> }

> Innocent as I am, I expected to see 5 here, but
> I get 6 or 4 depending on the compiler. Is this a
> case of some "for hard-core c programmers only"
> precedence rules?

Your code invokes undefined behavior, because it modifies the value of
t and takes its value for a purpose other than generating the new
value, without an intervening sequence point.

There is a sequence point between the two expressions inside each
parenthesized pair, but there is no sequence point between accessing
the value of t after the comma in the first pair, and the assignment
of 3.0 to t in the second pair.  The + operator does not create a
sequence point.

Since the behavior is undefined, neither compiler is wrong.

Jack Klein
--
Home: http://jackklein.home.att.net
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question

Quote:

>     x = (t=2.0, t) + (t=3.0, t);

[...]

Quote:
> Innocent as I am, I expected to see 5 here, but I get 6 or 4
> depending on the compiler. Is this a case of some "for hard-core c
> programmers only" precedence rules?

No, it's a case of undefined behaviour, I think. I.e. the compiler is
allowed to do *anything*, with this source code. It could generate a
program that asks you for a glass of vodka, or whatever.

At least, that's what my understanding of the side effect and sequence
point rules suggests the answer to be...
--

Even if all the snow were burnt, ashes would remain.
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question

Quote:

>     x = (t=2.0, t) + (t=3.0, t);
> Innocent as I am, I expected to see 5 here, but
> I get 6 or 4 depending on the compiler. Is this a
> case of some "for hard-core c programmers only"
> precedence rules?

Surely this must be in the C FAQ.  The simple fact is
that C implementations can interleave the processing
among the parenthesized terms in the above expression.
If you want to force an assignment to actually occur
before accessing the value of the variable, make sure
there is a sequence point between the two operations.
The easiest way to do that is to use semicolons and
a temporary variable:
        { register double old_t;
        t = 2.0;
        old_t = t;
        t = 3.0;
        x = old_t + t;
        }
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question


Quote:
> #include <stdio.h>
> int main(){
>     double x, t;
>     x = (t=2.0, t) + (t=3.0, t);

This is either identical to:

      t = 2.0;
      t = 3.0;
      x = t + t;  /* resulting in x == 6.0 */

or identical to:

      t = 3.0;
      t = 2.0;
      x = t + t;  /* resulting in x == 4.0 */

This depends on the order of evaluation or the left-hand and right-hand
sides of the + operator. This is allowed to be either one. And, as you
found out, depends on the compiler and sometimes a few other
circumstances.

Quote:
>     printf("x = %f\n", x);
>     return 0;
> }

> Innocent as I am, I expected to see 5 here, but
> I get 6 or 4 depending on the compiler. Is this a
> case of some "for hard-core c programmers only"
> precedence rules?

Order of evaluation problem in a statement with multiple side-effects.
Simply a very bad construct ...

Greetings from
 _____
 /_|__| Auke Reitsma, Delft, The Netherlands.
/  | \  -------------------------------------
        Remove NO_SPAM_ from my address ...
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question

Quote:

>     x = (t=2.0, t) + (t=3.0, t);
        ...
> Innocent as I am, I expected to see 5 here, but
> I get 6 or 4 depending on the compiler. Is this a
> case of some "for hard-core c programmers only"
> precedence rules?

Expressions with multiple side affects (changes which last beyond the
scope of the expression, such as variable assignments) to the same
object result in undefined behavior; it would be perfectly reasonable
for your program, under these conditions, to crash (though obviously
it's more likely that it simply won't do what you expect).

The issue is that the compiler is under no obligation to evaluate the
subexpressions in the order that you expect it to, for purposes of
optimization.

Even statements such as

     i = ++i;

are undefined.

--

    Alcyone Systems | web http://www.alcyone.com/max/
       San Jose, CA | languages en, eo | icbm 37 20 07 N 121 53 38 W
                USA | 962.442 Ms pL | 348 days left | &tSftDotIotE
 __
/  \ It is human nature to think wisely and act foolishly.
\__/ Anatole France
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question

Quote:

> #include <stdio.h>
> int main(){
>     double x, t;
>     x = (t=2.0, t) + (t=3.0, t);
>     printf("x = %f\n", x);
>     return 0;
> }
> Innocent as I am, I expected to see 5 here, but
> I get 6 or 4 depending on the compiler. Is this a
> case of some "for hard-core c programmers only"
> precedence rules?

No, this is a case of two changes to 't' between
adjacent sequence points. The starting sequence point
is the entry of main, the finishing sequence point
is the end of the assignment statement. Between
these, only one assignment to each value may
occur. Since you write twice to 't', you invoke
undefined behavior. The compiler may ignore
either write, use the value of t beforehand,
afterwards, or let the computer catch fire.
It is impossible to predict what happens when
undefined behavior occurs.

Michiel Salters
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question


Quote:
>#include <stdio.h>
>int main(){
>    double x, t;
>    x = (t=2.0, t) + (t=3.0, t);
>    printf("x = %f\n", x);
>    return 0;
>}

>Innocent as I am, I expected to see 5 here, but
>I get 6 or 4 depending on the compiler. Is this a
>case of some "for hard-core c programmers only"
>precedence rules?

Nothing to do with precedence rules but something to do with sequence
points.  While yje comma operator requires that its left operand be
completely evaluated and side effects completed before starting
evaluation of the right operand there is no such requirement for +.  The
result is that the compiler can legitimately evaluate t=2.0 and t=3.0
and the two evaluations of t in any order it likes as long as the above
constraint applies.  As it is possible to evaluate both the assignments
before either of the others the results are strictly undefined.  In the
cases you tested this did no more harm than shake up your thinking.  I
guess one compiler is evaluating t=3 first and the other is evaluating
t=2.  You are lucky that neither compiler did what you expected because
now you know about this kind of problem.

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



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question

Quote:

> This is either identical to:

>       t = 2.0;
>       t = 3.0;
>       x = t + t;  /* resulting in x == 6.0 */

> or identical to:

>       t = 3.0;
>       t = 2.0;
>       x = t + t;  /* resulting in x == 4.0 */

Actually, it's undefined behavior.  The compiler is free to generate a
program that does either of those things, calculate pi to a billion
decimal places, spout profanity, or just plain old crash.  Side effects
to the same object (in this case, t) without an intervening sequence
point (think:  statement, though there are other types of sequence
points such as initializations) results in undefined behavior.  A
compiler is free to generate a program which exhibits _any_ kind of
behavior.

--

    Alcyone Systems | web http://www.alcyone.com/max/
       San Jose, CA | languages en, eo | icbm 37 20 07 N 121 53 38 W
                USA | 962.442 Ms pL | 348 days left | &tSftDotIotE
 __
/  \ It is human nature to think wisely and act foolishly.
\__/ Anatole France
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question

Quote:



> > #include <stdio.h>
> > int main(){
> >     double x, t;
> >     x = (t=2.0, t) + (t=3.0, t);

> This is either identical to:

>       t = 2.0;
>       t = 3.0;
>       x = t + t;  /* resulting in x == 6.0 */

> or identical to:

>       t = 3.0;
>       t = 2.0;
>       x = t + t;  /* resulting in x == 4.0 */

No, it's not necessarily `identical' to either one of those
sequences.  Undefined behavior is just that: anything can happen,
including behavior you don't expect.
--



Mon, 08 Jul 2002 03:00:00 GMT  
 order of evaluation question


Quote:
>This is either identical to:

>      t = 2.0;
>      t = 3.0;
>      x = t + t;  /* resulting in x == 6.0 */

>or identical to:

>      t = 3.0;
>      t = 2.0;
>      x = t + t;  /* resulting in x == 4.0 */

Or absolutely anything else the compiler elects to do.  All you have
itemised is two reasonable options, but if you were right the result
would be unspecified.

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



Thu, 11 Jul 2002 03:00:00 GMT  
 
 [ 12 post ] 

 Relevant Pages 

1. Order of evaluation question

2. order of evaluation

3. order of evaluation?

4. Order of expression evaluation in C++

5. order in operator evaluation?

6. order of evaluation problem

7. ## preprocessing directive, and evaluation order

8. order of evaluation

9. Order of Evaluation vs. Associativity

10. Order of evaluation: | and ++

11. evaluation order/guarantee

12. Order of evaluation

 

 
Powered by phpBB® Forum Software