By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,882 Members | 2,482 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,882 IT Pros & Developers. It's quick & easy.

Unpredictable nature of increment operators

P: n/a
Why doe the following C++ code behaves as it does?

int i;

i=1; cout << (++i)++; Output: 2
i=1; cout << ++(++i); Output: 3
i=1; cout << (i++)++; Output: Error. LValue required
i=1; cout << ++(i++); Output: Error. LValue required
Jun 27 '08 #1
Share this Question
Share on Google+
8 Replies


P: n/a
bintom wrote:

Once is enough!

--
Ian Collins.
Jun 27 '08 #2

P: n/a
On May 8, 5:16 pm, bintom <binoythomas1...@gmail.comwrote:
Why doe the following C++ code behaves as it does?

int i;

i=1; cout << (++i)++; Output: 2
i=1; cout << ++(++i); Output: 3
i=1; cout << (i++)++; Output: Error. LValue required
i=1; cout << ++(i++); Output: Error. LValue required
Because code like that is so hard to read you would never actually
write it!

Also remember that it is illegal to modify a variable more than once
within the same expression [undefined behavior I believe](somebody
with a copy of the standard will be able to quote you chapter an verse
and the actual definition rather than my layman's wording).
Jun 27 '08 #3

P: n/a
Martin York wrote:
On May 8, 5:16 pm, bintom <binoythomas1...@gmail.comwrote:
>Why doe the following C++ code behaves as it does?

int i;

i=1; cout << (++i)++; Output: 2
i=1; cout << ++(++i); Output: 3
i=1; cout << (i++)++; Output: Error. LValue
required i=1; cout << ++(i++); Output: Error.
LValue required

Because code like that is so hard to read you would never actually
write it!

Also remember that it is illegal to modify a variable more than once
within the same expression [undefined behavior I believe](somebody
with a copy of the standard will be able to quote you chapter an verse
and the actual definition rather than my layman's wording).
Only a variable of a built-in type, and only if there is no sequence
point between the modifications. For example, it's not undefined
behaviour to do

f(i++) + ++i;

IIRC, but the results are unspecified. And if your class has the
operators ++() or ++(int) overloaded, the results are even well-
defined and predictable. For 'int' they aren't...

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 27 '08 #4

P: n/a
In article <d16e4f6a-c4f2-4b6f-bf7d-
ea**********@i76g2000hsf.googlegroups.com>, ja*********@gmail.com
says...
On 9 mai, 19:21, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
[ ... ]
For example, it's not undefined behaviour to do
f(i++) + ++i;

Yes it is, since there is no sequence point between the two
incrementations. Sequence points only define a partial
ordering: there is a sequence point before calling f, but that
only establishes and ordering between i++ and the call to f; it
doesn't establish any ordering between the two incrementations.
I believe it establishes _some_ ordering, but not enough[1]. In
particular, I believe the compiler is required to treat evaluation of a
function argument and calling the function as atomic -- i.e. once the
evaluation of any argument takes place, it must proceed to evaluated the
other arguments (if any) and then call the function.

In the expression above, I don't believe it's allowed for the post-
increment to be evaluated, then the pre-increment, then the function
call. It is, however, allowed for the pre-increment, then the post-
increment, then the function call -- and in this ordering, there is no
sequence point between the pre-increment and the post-increment, so the
result is undefined behavior.

1: Though it's open to some question. $1.9/8 says: "Once the execution
of a function begins, no expressions from the calling function are
evaluated until execution of the called function has completed."

I'm interpreting evaluating the arguments to a function as part of
execution of the function. If you choose to interpret it as a completely
separate act that happens before the function's execution, then you're
right -- no ordering is defined. At least in this case, it doesn't make
any real difference though -- the overall result is undefined behavior
either way.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 27 '08 #5

P: n/a
Jerry Coffin wrote:
In article <d16e4f6a-c4f2-4b6f-bf7d-
ea**********@i76g2000hsf.googlegroups.com>, ja*********@gmail.com
says...
>On 9 mai, 19:21, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:

[ ... ]
>>For example, it's not undefined behaviour to do
>> f(i++) + ++i;

Yes it is, since there is no sequence point between the two
incrementations. Sequence points only define a partial
ordering: there is a sequence point before calling f, but that
only establishes and ordering between i++ and the call to f; it
doesn't establish any ordering between the two incrementations.

I believe it establishes _some_ ordering, but not enough[1]. In
particular, I believe the compiler is required to treat evaluation
of a function argument and calling the function as atomic -- i.e.
once the evaluation of any argument takes place, it must proceed to
evaluated the other arguments (if any) and then call the function.

In the expression above, I don't believe it's allowed for the post-
increment to be evaluated, then the pre-increment, then the function
call. It is, however, allowed for the pre-increment, then the post-
increment, then the function call -- and in this ordering, there is
no sequence point between the pre-increment and the post-increment,
so the result is undefined behavior.

1: Though it's open to some question. $1.9/8 says: "Once the
execution of a function begins, no expressions from the calling
function are evaluated until execution of the called function has
completed."

I'm interpreting evaluating the arguments to a function as part of
execution of the function. If you choose to interpret it as a
completely separate act that happens before the function's
execution, then you're right -- no ordering is defined. At least in
this case, it doesn't make any real difference though -- the
overall result is undefined behavior either way.
I think your second interpretation is the correct one. It means that
++i can be evalueated before or after calling f, but not during.

However, evaluating the arguments is done before calling the function,
not as part of the call.

Breaking it down:

evaluating i++
sequence point
call function
return
sequence point
add
At the point of the add operation, the result of the right hand side
of the addition must be available. It must be evaluated somewhere
before the add operation, obviously, but not between the two sequence
points.

Bo Persson
Jun 27 '08 #6

P: n/a
In article <68*************@mid.individual.net>, bo*@gmb.dk says...

[ ... ]
1: Though it's open to some question. $1.9/8 says: "Once the
execution of a function begins, no expressions from the calling
function are evaluated until execution of the called function has
completed."

I'm interpreting evaluating the arguments to a function as part of
execution of the function. If you choose to interpret it as a
completely separate act that happens before the function's
execution, then you're right -- no ordering is defined. At least in
this case, it doesn't make any real difference though -- the
overall result is undefined behavior either way.

I think your second interpretation is the correct one. It means that
++i can be evalueated before or after calling f, but not during.
You could _certainly_ be right. As I said, in this case it doesn't
really make much difference, since either one gives undefined results.

I got curious and read through N2284, and found that the wording has
been changed to [intro.execution]/16:

Every evaluation in the calling function (including other
function calls) that is not otherwise specifically
sequenced before or after the execution of the body of
the called function is indeterminately sequenced with
respect to the execution of the called function.

This is apparently an attempt at clarifying the situation, but doesn't
seem (to me) to add much clarity. In particular, it specifically cites
execution of the body of the function in one place, but execution of the
called function in the other. It's not at all clear whether this is just
mildly sloppy wording, and the two are intended to be synonymous, or
whether it's completely intentional, and intended to delineate between
the two.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 27 '08 #7

P: n/a
On 10 mai, 17:01, Jerry Coffin <jcof...@taeus.comwrote:
In article <d16e4f6a-c4f2-4b6f-bf7d-
ea1258da7...@i76g2000hsf.googlegroups.com>,
james.ka...@gmail.com says...
On 9 mai, 19:21, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
[ ... ]
For example, it's not undefined behaviour to do
f(i++) + ++i;
Yes it is, since there is no sequence point between the two
incrementations. Sequence points only define a partial
ordering: there is a sequence point before calling f, but
that only establishes and ordering between i++ and the call
to f; it doesn't establish any ordering between the two
incrementations.
I believe it establishes _some_ ordering, but not enough[1].
In particular, I believe the compiler is required to treat
evaluation of a function argument and calling the function as
atomic -- i.e. once the evaluation of any argument takes
place, it must proceed to evaluated the other arguments (if
any) and then call the function.
Where do you get that? I've used compilers which violate it,
and I'm fairly sure that it is neither required by the standard,
nor was it the intent. There was even a DR for C, the answer of
which made it quite clear that the only reordering which isn't
allowed is intervening the actual execution of the function with
other parts of the expression.
In the expression above, I don't believe it's allowed for the
post- increment to be evaluated, then the pre-increment, then
the function call. It is, however, allowed for the
pre-increment, then the post- increment, then the function
call -- and in this ordering, there is no sequence point
between the pre-increment and the post-increment, so the
result is undefined behavior.
1: Though it's open to some question. $1.9/8 says: "Once the
execution of a function begins, no expressions from the
calling function are evaluated until execution of the called
function has completed."
I'm interpreting evaluating the arguments to a function as
part of execution of the function.
That's the first time I've heard that interpretation. The
classical example of undefined behavior in C is:
f( i++ ) + f( i ++ )
If you choose to interpret it as a completely separate act
that happens before the function's execution, then you're
right -- no ordering is defined. At least in this case, it
doesn't make any real difference though -- the overall result
is undefined behavior either way.
In practice, I'd say that if you have to ask the question, the
code is probably doing something it shouldn't anyway:-). For
readability's sake, even if it is defined. But the classical
interpretation, at least within the C committee (many years ago)
was that the execution of the function is what happens between
the sequence point entering the function, and the sequence point
leaving it.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #8

P: n/a
On 11 mai, 17:05, Jerry Coffin <jcof...@taeus.comwrote:
In article <68nqmmF2u7p5...@mid.individual.net>, b...@gmb.dk says...
[ ... ]
1: Though it's open to some question. $1.9/8 says: "Once
the execution of a function begins, no expressions from
the calling function are evaluated until execution of the
called function has completed."
I'm interpreting evaluating the arguments to a function as
part of execution of the function. If you choose to
interpret it as a completely separate act that happens
before the function's execution, then you're right -- no
ordering is defined. At least in this case, it doesn't
make any real difference though -- the overall result is
undefined behavior either way.
I think your second interpretation is the correct one. It
means that ++i can be evalueated before or after calling f,
but not during.
You could _certainly_ be right. As I said, in this case it
doesn't really make much difference, since either one gives
undefined results.
I got curious and read through N2284, and found that the
wording has been changed to [intro.execution]/16:
Every evaluation in the calling function (including other
function calls) that is not otherwise specifically
sequenced before or after the execution of the body of
the called function is indeterminately sequenced with
respect to the execution of the called function.
This is apparently an attempt at clarifying the situation, but
doesn't seem (to me) to add much clarity.
This isn't so much an attempt at clarifying the situation, as at
making the text relevant in a multithreaded environment.

I'm pretty sure that there was a DR in C which made this clear;
the actual question was different (could the compiler interleaf
the execution of two functions), but the text in the
clarification made it clear that just about any reordering is
permitted before the actual function call and after the return.
(This is from memory, however; I have no idea how to go about
finding the actual DR, and it's quite possible that I'm basing
my opinion on discussions concerning the DR, and not only on the
formal answer to it.)
In particular, it specifically cites execution of the body of
the function in one place, but execution of the called
function in the other. It's not at all clear whether this is
just mildly sloppy wording, and the two are intended to be
synonymous, or whether it's completely intentional, and
intended to delineate between the two.
In general, I think that there is a fairly widespread consensus
that the way C describes sequence points, and the way they
establish an ordering, is far from optimal. The C committee
decided to not address the issue in the C99 revision, on the
grounds that while far from optimal, it was sufficient, and
there was no real indication that any of the proposed
alternatives were better (i.e. clearer). Unless you want to
specify ordering fully, as in Java, it's a difficult issue to
define precisely when to stop. The philosophy of sequence
points doesn't work at all in a multithreaded environment,
however, so the C++ committee is obliged to find something else.
Hopefully, clearer, but unless you define full ordering, it's
difficult to be really clear (and requiring full ordering in a
multithreaded environment has a number of additional
problems---even Java punts on this one, resulting in what would
be called in C++ "undefined behavior").

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #9

This discussion thread is closed

Replies have been disabled for this discussion.