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

C++ Operator precedence, evaluation order, sequence points

8 views
Skip to first unread message

Jim Cassidy

unread,
Apr 9, 2003, 1:48:42 AM4/9/03
to
Caution: The following code is pure evil and this is only an
exercise. This post is long and likely to steal time from your life
you'll never get back.

Consider this code in C++.

Example 1:

int x = 1;
x += ++x + --x;

results in

x = 3 in VC 6 and VC 7, GCC 2.95 in Cygwin and Forte 7 C 5.4 on SunOS
5.8
x = 4 with gcc 3.2 on SunOS 5.8 and on HPUX (unknown compiler and
version)
x = 4 in C# and Java, for what it's worth

If x is replaced with an object that provides the appropriate
overloaded methods and operators and works like an int, then

Foo x = 1;
x += ++x + --x;

x = 3 in VC 6 and 7 and GCC 2.95 in Cygwin

Now, some analysis:

x = 1; x += ++x + --x;

We would expect x = 4 IF the operands are evaluated from left to right
(which they appear to be when analyzing the assembly from VC7) and if
we keep the value of ++x (2) for later evaluation in the expression
and then decrement x to 1 and keep that value, resulting in 1 += 2 + 1
=> 4. However, four different compilers give 3. The assembly from
VC7 shows the compiler loading registers with the value of x after the
pre-decrement and performing, essentially, 1 += 1 + 1. Now, If we
replace x with an object of type Foo as described above, then we get x
= 3, but the interesting bit is that (in VC7 and GCC 2.95 on Cygwin)
the pre-decrement operator is invoked first, then the pre-increment,
and then the addition, and then the +=. So, the order of evaluation
is one way when the operations are on a primitive type and another
when the operations are on an object.

Now, as far as the difference between x = 3 and 4 as the result, even
when the the order of evaluation is left to right, I think that that
is because the statement x += ++x + --x; actually results in
"undefined" behavior C++, because the standard (I'm going with what
I've found at http://www-cpd.fnal.gov/personal/wb/boost/ISOcxx/doc/Expressions.html)
states that

"the value of a scalar object may be modified no more than once
between any two consecutive sequence points. If it is modified, use
of the prior value is restricted and may only be used in determining
what new value is to be stored. These requirements must be met for
all possible orders in which a full-expression's subexpressions may be
evaluated. Failure to meet all of these requirements results in
"undefined" behavior " (down in part 6).

Now, I don't completely understand this statement, but I think it
means that, since we modify x three times with only one sequence point
(++x, --x, and x += ... and the only sequence point is the statement
itself) we have created code that has undefined behavior.

Example 2:
int x = 4;
x = 2 + x++ * 3;

results in

x = 15 in VC 6 and VC 7, GCC 2.95 in Cygwin and Forte 7 C 5.4 on SunOS
5.8
x = 14 on HPUX (unknown compiler and version)
x = 5 in gcc 3.2 on SunOS
x = 14 in C# and Java, for what it's worth

Analysis:

We would expect x = 14 IF we take the value of x and keep it (prior to
the post increment, whose results would eventually be overwritten by
the assignment), then do 4 * 3, then 2 + 12, and then assign 14 to x.
Now, the 15 result from so many compilers is really surprising, and
looking at the assembly generated from VC 7, we see that the post
increment of x is performed after the assignment. Now, during some
googling I saw some mention of this effect, but it was surprising to
me, since the post increment operator has precedence over the
assignment operator. Can someone explain if this is due to some
sequence point rule or is some other operator precedence or evaluation
order rule causing this. This case looks like valid code, I'm
surprised to see so many different answers. The 5 from GCC 3.2 is
surprising, too. I think that what's happening here is that the
expression is being evaluated with x = 4, the results thrown away, x
incremented to 5 and then assigned to x.

So, to wrap this all up. Obviously, this code is resulting in
different behavior on different platforms. Note that all the
compilers eat this code and compile without warning. PC-Lint gets all
upset and complains about the code relying order of evaluation. I'm
not sure if that's the only thing wrong with the above code.

I'm trying to decide whether the code above is right and being
incorrectly evaluated, using "undefined" behavior, illegal or just
plain evil. I'll maintain that this code is pure evil, and anyone
writing this should be covered in honey and staked to an ant hill.
But, I'm not sure if:

1. The code is invalid/undefined because of sequence point
restrictions.
2. The code is invalid/undefined because of the lack of order of
evaluation guarantees. (Stroustroup, "The C++ Programming Language",
3rd Edition, section 6.2.2.
3. The code is invalid/undefined because of an order of evaluation
rule I don't understand.
4. The code is invalid/undefined because of some precedence rule I
don't understand.
5. The code is invalid/undefined because of a combination of the
above.
6. The code is okay (if so, which compiler is "right", 4 and 14, as
the answers, seem "rightest" to me).

So, can anyone help clarify these results for me?

Thanks,
Jim

Attila Feher

unread,
Apr 9, 2003, 1:54:52 AM4/9/03
to
Jim Cassidy wrote:
> Caution: The following code is pure evil and this is only an
> exercise. This post is long and likely to steal time from your life
> you'll never get back.
>
> Consider this code in C++.
>
> Example 1:
>
> int x = 1;
> x += ++x + --x;
>
> results in
[SNIP]

Undefined behaviour. That is all you need to know. From that point on your
are not talking C++, but something undefined/uninteresting/nono/tabu.

About you answers: 1 and 2 are right. There is no fixed evaluation order.
Only that up to a sequence point all will be evaluated. And 5 is true,
since 1 and 2 is a combination. :-)

Why don't you read the FAQ? http://www.eskimo.com/~scs/C-faq/s3.html I
know, it is the C one, but there is sequence point and all that - described.

A


Ivan Vecerina

unread,
Apr 9, 2003, 2:18:14 AM4/9/03
to
"Jim Cassidy" <JimCa...@mail.com> wrote in message
news:f48df558.03040...@posting.google.com...
Example 1: direct use of scalar
: int x = 1;

: x += ++x + --x;

Example 2: use of int-wrapper with adequate operator overloads:
: Foo x = 1;


: x += ++x + --x;

: So, to wrap this all up. Obviously, this code is resulting in


: different behavior on different platforms. Note that all the
: compilers eat this code and compile without warning. PC-Lint gets
all
: upset and complains about the code relying order of evaluation.
: I'm not sure if that's the only thing wrong with the above code.

It is the only thing wrong when x is a user-defined class with
custom, overloaded operators. Whether op++ or op-- is called first
will change the result of the expression, and the compiler is
free to choose any evaluation order as it deems fit.

When x is a built-in type, the behavior is explicitly undefined,
as described in your quote of the C++ standard: within sequence
points, an expression may only modify the value of a variable
once.

: int x = 4;


: x = 2 + x++ * 3;

Here, x is updated either by operator++, or by the assignment.
This is undefined behavior: x may have ANY value after this
statement is executed (and may theoretically crash your system,
etc...).

Regards,
--
Ivan Vecerina, Dr. med. <> http://www.post1.com/~ivec
Soft Dev Manger, XiTact <> http://www.xitact.com
Brainbench MVP for C++ <> http://www.brainbench.com


Spike

unread,
Apr 9, 2003, 5:22:11 AM4/9/03
to

"Jim Cassidy" <JimCa...@mail.com> wrote in message
news:f48df558.03040...@posting.google.com...
> Caution: The following code is pure evil and this is only an
> exercise. This post is long and likely to steal time from your life
> you'll never get back.
>

you are right. it was positively Satanic. I for one had to get my house
exorcised immediately after reading the first paragraph :-)

0 new messages