5

Possible Duplicates:
What is more efficient i++ or ++i?
How do we explain the result of the expression (++x)+(++x)+(++x)?
Difference between i++ and ++i in a loop?

I am trying these two programs:

void fun(){
     int k = 0;
     int i= 10;
     k = (i++)+(++i);
     cout << k << endl;
}

Output = 22 as i++ will give 10 and ++i will evaluate into 12.

But

void fun(){
     int k = 0;
     int i = 10;
     k = (++i)+(++i);
     cout << k << endl;
}

Output = 24

It should be 23 I guess, or is there something that I am not able to see?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
aR.
  • 51
  • 2
  • 5
    No, the output for both is undefined (or implementation-defined) because the standard makes no guarantee what order the items in an expression are evaluated. – Chris Lutz Nov 05 '09 at 05:30
  • my prof said i++ should be avoided, i+=1 is safer in c++ – derrdji Nov 05 '09 at 05:30
  • 2
    @derrdji - Your professor is a bit overly cautious, and also ignoring situations where the precedence and/or evaluation rules of `i++` and `++i` are quite useful. The fact that something can be abused doesn't mean that you shouldn't learn how to use it properly. – Chris Lutz Nov 05 '09 at 05:32
  • @derrdji: Why. The only different is that i++ can be used in an expression. – Martin York Nov 05 '09 at 05:35
  • @Chris - I think I understand why ++i is useful, but isn't i++ the same as i+=1? and also, what I learned was having assignments in expression should always be avoided, is that not true outside of classes? – derrdji Nov 05 '09 at 05:35
  • 3
    @aR: Neither program is valid. Modifying a variable more than once in a statement is undefined behavior. – Martin York Nov 05 '09 at 05:37
  • @derrfji: x = i++ (postscript increment) is the same as x = i; i += 1. As such, it can be useful to write an algorithm in a more compact way. You should be careful when using postscript increment with iterators, though, because it might imply the construction of a temporary object - potentially a costly operation. But there's nothing wrong with incrementing integers that way. Try implementing strcpy() without it, and compare with char * rc = s1; while ( ( *s1++ = *s2++ ) ); return rc; for compactness and readability... – DevSolar Nov 05 '09 at 05:48
  • 2
    @derrdji - No, they have different precedences and order of evaluations. `j = i++;` and `j = i += 1;` produce different results (j is 5 in the first one and 6 in the second). – Chris Lutz Nov 05 '09 at 05:49
  • 1
    @derrdji - avoiding pre/post increment/decrement within an expression is a stylistic preference. But even if you decide never to do that yourself, you need to be prepared to work with code from other developers who do not follow the same style. – R Samuel Klatchko Nov 05 '09 at 05:50
  • @aR - What is the output you are getting for the second case? 23 or 24 – Himadri Nov 05 '09 at 05:58
  • undefined http://stackoverflow.com/questions/1525187/how-do-we-explain-the-result-of-the-expression-xxx – Rohit Banga Nov 05 '09 at 06:50

10 Answers10

19

Note: you are invoking undefined behavior (modifying a variable twice between sequence points)

Brian
  • 1,810
  • 12
  • 9
  • 1
    Brian's is the correct answer. This is paragraph 2 of ANSI C standard section 6.3 "Expressions" -- "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored." – Heath Hunnicutt Nov 05 '09 at 05:38
  • 9
    It's a bit scary to see how many people answered the question *without* catching the undefined part. Sadly enough, still most people consider whatever works with their compiler and test cases to be "valid"... – DevSolar Nov 05 '09 at 05:51
  • I think the reason why people answered (including me) is that the question is "What is going on?". I think many people just try to explain why based on the behaviors that is visible. I personally never use '++' operator except in for loop. – NawaMan Nov 05 '09 at 06:17
  • 1
    But the point is, if behaviour is *undefined* as by spec, any explanation of "what is going on" is uncertain at best, and keeps the OP unaware of the potentially fatal programming flaw at worst. – DevSolar Nov 05 '09 at 11:55
6

According to C++03 Standard 5/4 the behavior of the programs in question is undefined:

Except where noted, the order of evaluation of operands of individual operators and subexpressions of indi- vidual expressions, and the order in which side effects take place, is unspecified. 53) Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
4

This seemed really interesting, so I took a peek at the disassembly (MSVC++2008)

     k = (++i)+(++i);
0122413C  mov         eax,dword ptr [i] 
0122413F  add         eax,1 
01224142  mov         dword ptr [i],eax 
01224145  mov         ecx,dword ptr [i] 
01224148  add         ecx,1 
0122414B  mov         dword ptr [i],ecx 
0122414E  mov         edx,dword ptr [i] 
01224151  add         edx,dword ptr [i] 
01224154  mov         dword ptr [k],edx 

As you can see, it increments i twice and then adds i to itself. The same thing happens if there are multiple instances of (++i).

Anyway, since the Standard doesn't guarantee anything, modifying i more than once will lead to undefined behaviour.

Jacob
  • 34,255
  • 14
  • 110
  • 165
2

A variable never should be increased more than one time within one statement, because the behaviour of the compiler isn't defined.

To avoid side effects, make two statements for your examples.

Example 1: k = i++; k += ++i;

Example 2: k = ++i; k += ++i;

If you do so, your code will work correctly.

0

I'm guessing that both pre-increment operators are running before the addition statement gets calculated. hence 24.

All depends on how the compiler sees what you're doing, but I'm guessing that's what you're seeing.

Deeksy
  • 5,304
  • 2
  • 23
  • 27
0

i++ is post-increment, ++i is pre-increment. i++ will increment i after the statement is completed.

To illustrate in your examples:

Example 1:

k = 0
i = 10

i += 1
k = i + i  // 11 + 11
i += 1

Example 2:

k = 0
i = 10

i += 1
i += 1
k = i + i  // 12 + 12
Josh
  • 3,540
  • 1
  • 21
  • 12
  • Man! Your explanation is much more concise. :-D – NawaMan Nov 05 '09 at 05:45
  • 1
    It's also equally incorrect. The OP's code invokes undefined behavior, which this code does not do because `i` is never assigned to more than once in any statement. Therefore, the OP's code can do anything the compiler writers want it to, but this code will be well-defined for all compilers. It's useless to try to explain undefined behavior, and much better to rewrite it to be defined behavior. – Chris Lutz Nov 05 '09 at 05:52
  • 1
    This doesn't really answer the question of why the compiler sees it this way rather than assigning the result to two temporaries and then adding both of those. – Ken Bloom Nov 05 '09 at 06:01
-1

++i will give result i=i+1. If i=10 then in k = (++i)+(++i); expression (++i) will give incremented value that means first increment will happen but in case of i++ the increment will be affected on i after the expression.

So i=10

k = (i++) + (++i);

 10    11   12

 10    +  12=22  

k = (++i) + (++i);

 11   11  12

  11   +  12=23
Himadri
  • 8,600
  • 15
  • 47
  • 70
  • But he wants to know why he gets 24 where you just got 23 doing it by hand. – Ken Bloom Nov 05 '09 at 05:51
  • 1
    The results are dependent on how the compiler re-orders sub-expressions within the output code. So there are actually multiple different valid solutions (valid for a compiler engineer standpoint not from a language stand point). – Martin York Nov 05 '09 at 11:21
-1

++i usually returns a reference to the variable itself so the second modification also affects the memory that holds the result from the first modification. (Post-increment i++, on the other hand, has to return a copy of the value in order to work properly.)

A typical definition of ++i in C++ (using operator overloading) would be

struct Foo{
  //...
  Foo const & operator++(){ //this implements ++i
    //do something to increment
    return *this;
  }
  Foo operator++(int){ //this implements i++
    Foo old(*this);
    //do something to increment
    return old;
  }
};
Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
  • @kbloom, you'd normally implement the post-increment operator in terms of the pre-increment operator. So your comment "//do something to increment" in your post-increment operator would simply invoke the pre-increment operator. See Herb Sutter's Guru of the Week article for details: http://www.gotw.ca/gotw/004.htm – Void - Othman Nov 05 '09 at 06:06
  • That's certainly true. My point, however, was to explain why both pre-increment operators seem to return even numbers (or why both seem to return odd numbers) when it would seem that one should return an even number and one should return an odd number. The answer to that is that preincrement returns the actual memory location of the value that was incremented -- not a copy. – Ken Bloom Nov 05 '09 at 15:19
-2

++i happens before calculating the whole expression and i++ happens after. In the first example one of increments happen before calculating the value, so "i" becomes 21 and you get 21 + 21. In the last example both happen before, so "i" becomes 22 and you get 22 + 22.

Paul Graphov
  • 306
  • 4
  • 11
-2

To determine this the following step is taking.

1). All of ++i is determined.

2). The value of i is then used to each term that is ++i and i++.

3). All of i++ is determined.

First case:

     int k=0;
     int i=10;
     k = (i++)+(++i);

1) There is one of ++i so at then end of this step i = 11 (once).

2) Now it become k = (11)+(11);

3) There is one of i++ so at then end of this step i = 12 (once).

Second case:

     int k=0;
     int i=10;
     k = (++i)+(++i);

1) There is one of ++i so at then end of this step i = 12 (twice).

2) Now it become k = (12)+(12);

3) There is one of i++ so at then end of this step i = 12 (zero time).

I create a test code:

#include <stdio.h>
int main(void) {
    int K=0;
    int I=10;
    K = (I++)+(++I);
    printf("I: %d; K: %d\n", I, K);

    K=0;
    I=10;
    K = (++I)+(++I);
    printf("I: %d; K: %d\n", I, K);
}

When executed, the result is:

I: 12; K: 22
I: 12; K: 24

Hope this helps.

NawaMan
  • 25,129
  • 10
  • 51
  • 77
  • So, in your example, the FIRST case should print an odd number (that's what you got when you did it by hand), but it printed an even number when you ran it. He wants to know what's up with that. – Ken Bloom Nov 05 '09 at 05:52
  • How can it be an odd number, (11)+(11) is 22 not an odd number. Please read number 2) carefully, the value of `++i` is used for both `++i` and `i++` because i of `i++` will be increased later (so before it is increased, it is 11 as it was increased by `++i`). That is why, K is (11)+(11). – NawaMan Nov 05 '09 at 06:11
  • There's no determenistic explanation for the program's behavior because the behavior is undefined. In practice, the result will differ from one compiler to another, for different translation settings in the same compiler, and even for differetn contexts in the same program. The "explanation" that you provided is completely useless, since the actual behavior is essentially random. – AnT stands with Russia Nov 05 '09 at 08:13
  • If I replaced ++i with a function int preincrement(int* x), and called it as preincrement(&i), then the compiler would fill two registers with the distinct return values of preincrement(). One of these would be even, and one would be odd (even though it's undefined in which order these functions would be called). The fact that the C compiler treats the ++ operator differently is odd, to say the least. The only operators in C that returns the exact same memory that they operated on are ++ and =. Everything else is forced to return a copy, or a pointer that you have to explicitly dereference. – Ken Bloom Nov 05 '09 at 15:52