The result of your code will be the same. The reason is that the two incrementation operations can be seen as two distinct function calls. Both functions cause an incrementation of the variable, and only their return values are different. In this case, the return value is just thrown away, which means that there's no distinguishable difference in the output.

However, under the hood there's a difference: The post-incrementation i++ needs to create a temporary variable to store the original value of i, then performs the incrementation and returns the temporary variable. The pre-incrementation ++i doesn't create a temporary variable. Sure, any decent optimization setting should be able to optimize this away when the object is something simple like an int, but remember that the ++-operators are overloaded in more complicated classes like iterators. Since the two overloaded methods might have different operations (one might want to output "Hey, I'm pre-incremented!" to stdout for example) the compiler can't tell whether the methods are equivalent when the return value isn't used (basically because such a compiler would solve the unsolvable halting problem), it needs to use the more expensive post-incrementation version if you write myiterator++.

Three reasons why you should pre-increment:

You won't have to think about whether the variable/object might have an overloaded post-incrementation method (for example in a template function) and treat it differently (or forget to treat it differently).

I think that you are wrong! The only difference between ++i and i++ is the order that you do things. In one case you would inc *i push *i and in the other you would push *i inc *i I would not concider this an optimization.
–
G. Allen Morris IIINov 27 '12 at 22:55

4

He's not wrong. Post-incrementing primitives when you don't use the copy can get optimized out quite easily by compilers. But the point he's alluding to in the last bit is that post-incrementing on iterators is implemented as a method call and the construction of an entirely new copy of the iterator. These can't be optimized out by the compiler because constructors and function calls can have side effects the compiler can't track and therefore can't assume aren't critical.
–
JhericoFeb 4 '14 at 21:17

The third statement in the for construct is only executed, but its evaluated value is discarded and not taken care of.
When the evaluated value is discarded, pre and post increment are equal.
They only differ if their value is taken.

This is one of my favorite interview questions. I'll explain the answer first, and then tell you why I like the question.

Solution:

The answer is that both snippets print the numbers from 0 to 4, inclusive. This is because a for() loop is generally equivalent to a while() loop:

for (INITIALIZER; CONDITION; OPERATION) {
do_stuff();
}

Can be written:

INITIALIZER;
while(CONDITION) {
do_stuff();
OPERATION;
}

You can see that the OPERATION is always done at the bottom of the loop. In this form, it should be clear that i++ and ++i will have the same effect: they'll both increment i and ignore the result. The new value of i is not tested until the next iteration begins, at the top of the loop.

Edit: Thanks to Jason for pointing out that this for() to while() equivalence does not hold if the loop contains control statements (such as continue) that would prevent OPERATION from being executed in a while() loop. OPERATION is always executed just before the next iteration of a for() loop.

Why it's a Good Interview Question

First of all, it takes only a minute or two if a candidate tells the the correct answer immediately, so we can move right on to the next question.

But surprisingly (to me), many candidates tell me the loop with the post-increment will print the numbers from 0 to 4, and the pre-increment loop will print 0 to 5, or 1 to 5. They usually explain the difference between pre- and post-incrementing correctly, but they misunderstand the mechanics of the for() loop.

In that case, I ask them to rewrite the loop using while(), and this really gives me a good idea of their thought processes. And that's why I ask the question in the first place: I want to know how they approach a problem, and how they proceed when I cast doubt on the way their world works.

At this point, most candidates realize their error and find the correct answer. But I had one who insisted his original answer was right, then changed the way he translated the for() to the while(). It made for a fascinating interview, but we didn't make an offer!

Well, you should reconsider asking this interview question because you made a grave but common mistake. A for loop can not be rewritten as you've specified in general. Look at for(int i = 0; i < 42; i++) { printf("%d", i); continue; } for example. Your claim is that it is semantically equivalent to int i = 0; while(i < 42) { printf("%d", i); continue; i++; } and that's clearly wrong.
–
JasonJan 16 '11 at 15:45

3

@Jason: And today I learned the edge case that I hadn't considered! In almost a decade, I've never had a candidate recognize this. If I continue to use this question, which is valuable for the reasons I mentioned, I'll be sure to rephrase it per the edits above. And if a candidate offers the correct answer immediately, I'll ask if there are any exceptions. :-) +1 for your clear counter-example. Thank you!
–
Adam LissJan 16 '11 at 15:56

@Jason, am I missing something or doesn't your answer to the question state the same. @Adam Liss, I think you're right in your statement, see the complement to my answer. You can indeed also implement the continue quite easily.
–
jdehaanJan 16 '11 at 16:22

@Adam Liss: Anyway, I think a nice interview question might be "rewrite an arbitrary for loop as a while loop." Almost surely you get your version. Ask if they are sure it's correct, and prod them by asking what happens if there is a continue in the body of the for loop and see if they can fix it. The reason I don't like your initial interview question is because their GPA in their CS classes will tell you whether or not they understand pre vs. post-increment.
–
JasonJan 16 '11 at 16:23

1

@Jason: Yes, I typically start with what looks like a simple interview question, and then "dig" a bit depending on the candidate's answer. Most of my experience until now has been with a tiny engineering company that tended to avoid new grads and favored EEs over developers who'd focused more on CS. (Not a judgment on my part, just the way it was.) In any case, I'm glad my answer led to this discussion and appreciate your thoughts.
–
Adam LissJan 16 '11 at 18:07

Because in either case the increment is done after the body of the loop and thus doesn't affect any of the calculations of the loop. If the compiler is stupid, it might be slightly less efficient to use post-increment (because normally it needs to keep a copy of the pre value for later use), but I would expect any differences to be optimized away in this case.

It might be handy to think of how the for loop is implemented, essentially translated into a set of assignments, tests, and branch instructions. In pseudo-code the pre-increment would look like:

set i = 0
test: if i >= 5 goto done
call printf,"%d",i
set i = i + 1
goto test
done: nop

Post-increment would have at least another step, but it would be trivial to optimize away

set i = 0
test: if i >= 5 goto done
call printf,"%d",i
set j = i // store value of i for later increment
set i = j + 1 // oops, we're incrementing right-away
goto test
done: nop

Well, this is simple. The above for loops are semantically equivalent to

int i = 0;
while(i < 5) {
printf("%d", i);
i++;
}

and

int i = 0;
while(i < 5) {
printf("%d", i);
++i;
}

Note that the lines i++; and ++i; have the same semantics FROM THE PERSPECTIVE OF THIS BLOCK OF CODE. They both have the same effect on the value of i (increment it by one) and therefore have the same effect on the behavior of these loops.

This is because in first block of code j sees the value of i after the increment (i is incremented first, or pre-incremented, hence the name) and in the second block of code j sees the value of i before the increment.