Hi all...
I tried the following code in my Turbo C++ ..

int j=5;
cout<<++j + ++j + j++;

and got the result 20, as expected.

But, when I replaced the code and assigned the same to another variable x, it gives result 21.
ie,

int j=5,x;
x= ++j + ++j + j++;
cout<<x;

gives 21 against the expected value, 20

More interestingly,
if I assign it to same variable j, by replacing x

int j=5;
j=++j + ++j + j++;
cout<<j;

It gives 22 as the output.

Can anyone help please? I am a Computer Science teacher and need urgent help...!

Edited 6 Years Ago by Nick Evan: Added code-tags

It's called undefined behavior. On your PC with your OS and your compiler, this could be the output. But there's no guarantee that it's the same on someone else's PC.

Comments
Yes indeed.

Wow! that's something creepy... trying this, it helps me understand why this is how it is:

int main(){

	{
        int j=5;
        std::cout << ((++j) + (++j)) + (j++) << std::endl;
        }
	{
        int j=5;
        std::cout << ((++j) + (++j)) << std::endl;
        }
        {
        int j=5;
        int x = ++j;
        x += ++j;
        x += j++;
        std::cout << x << std::endl;
        }
        {
        int j=5;
        j = ++j + ++j + j++;
        std::cout << j << std::endl;
        }
 
        return 0;
}

The output is:
21
14
20
22
At least on my computer.

I think the problem here is that the operator ++j will take the value of j after the whole expression evaluation. This explains the second case in my example, j is pushed, then incremented twice, then the values of both ++j terms are set to the value then (which will be 7), and are finally added. If you apply the same logic to the first case, the initial value of j is 5, so that is the return value of expression j++, then after two ++j and one j++, the final value of j is 8, so 8 + 8 + 5 = 21.

But the last case, I can't figure this one out, let me think about it a bit more. I think I will avoid using complex expressions with many ++ operators in the future, I guess that's what you should tell students too.

Edited 6 Years Ago by mike_2000_17: n/a

I guess this really is a case of undefined behaviour, because there is so much space for weird optimizations because of ambiguous operator priority... in any case, I think I cracked the last case giving 22. This is a pseudo-assembly code I can come up with to explain it:

// ((++j) + (++j)) + (j++) gives the following:
PUSH J,R1
COPY R1,R2
INC R1,1    //do first ++j
INC R1,1    //do second ++j
INC R1,1    //do j++
//now, R1 = 8, R2 = 5
COPY R1,RES //add ++j to result
ADD R1,RES  //add ++j to resul
ADD R2,RES  //add j++ to result
//now RES = 21

// j = ++j + ++j + j++; gives the following:
PUSH J,R1
INC R1,1    //do first ++j
INC R1,1    //do second ++j
//now, R1 = 7
COPY R1,R2  //copy initial value of j
//since initial value of j (R2) is equal to result of j++, the addition can be done now.
ADD R1,R1   //optimized addition of j = j + j to simply j += j
ADD R2,R1   //now add "initial value" of j.
//now R1 = 21 (3 x 7)
INC R1,1    //do j++
MOVE R1,J
//now J = 22

Edited 6 Years Ago by mike_2000_17: n/a

It's called side effects, it is generally not a good idea to program statements like this because of the unpredictability of them. This unpredictability comes partially from operator precedence, but not entirely. The increment and decrement operators have higher precedence than multiplication, division, and modulus, and postfix versions have higher precedence than prefix version. As a result, they are most likely not applying when you think they are.

In the second version, the pre-increment operators are applying to the temporary values produced, not j itself (temp values in red):

int j = 5, x;

//theoretical step by step:
x= ++j + ++j + j++;

/*becomes*/ x = ++5 + ++5 + 5++;
/*becomes*/ x = ++[B]6[/B] + ++[B]6[/B] + 5;
/*becomes*/ x = [B]8[/B] + [B]8[/B] + 5;
/*becomes*/ x = [B]16[/B] + 5;
/*becomes*/ x = [B]21[/B];
/*becomes*/ x = 21;

I have absolutely no clue about the third situation, but I get the same results as you on both VC++ 2008 and Code::Blocks... It is best not to speculate on undefined behavior, simply knowing that it's undefined should be enough.

Edited 6 Years Ago by Fbody: n/a

@Fbody >>simply knowing that it's undefined should be enough.
I agree, but isn't it fun to speculate!

>>postfix versions have higher precedence than prefix version
Oh.. that destroys my explanation of that case that give 22.

A table showing precedence (it's a tall page, the table is at the bottom). According to that, postfix versions are only 1 level above prefix versions, so they're similar, but there is a difference.

Edited 6 Years Ago by Fbody: n/a

hi
i too have the same doubt
can anyone explain the reason why it behaves like this

i am computer science student
help plzzzzz...

Comments
This post hurts my eyes
How about reading the thread?

guys go through the operator overloading for increment operators and u will understand everything.
because here all is so called computer science student i want u to try urself.
then ask me me if u dont get it.
its realy easy
and its not random at all

Comments
jerk

@bibhay:
>> and its not random at all
Of course it's not random, NOTHING is random on a computer! We, advice-giving posters, would be very retarded if we even thought so (did you see us mention it to be random anywhere in the thread?). It's UNDEFINED BEHAVIOUR, meaning the standard specifications alone are not enough to predict the result, it's either compiler-specific (and compiler-option-specific) or OS-specific... but of course, not random! Just completely undependable and thus to be avoided for robust coding.

BTW I'm not a computer science student, I learned everything on a try-it-myself basis (counting the LOCs in the millions) and I agree that the nose-in-the-textbook approach is almost completely useless. But that's no reason to be a snob to those who are learning and trying to understand what is happening in their _trial_ / example codes.

I tried the following code in my Turbo C++ ..

int j=5;
cout<<++j + ++j + j++;

and got the result 20, as expected.

Your first mistake is having any expectations at all about this statement.

It tries to modify the value of j twice (or more) in the same expression (or, more accurately, between two sequence points), so the result is undefined.

This means that a C++ compiler is permitted to generate code that does anything at all when you try to execute this statement, including deleting all your files and sending hate mail to all your friends.

This article has been dead for over six months. Start a new discussion instead.