Actually, if you do C++, it is much better to get used to write ++i
instead. The reason is simple: i++
requires a copy.
a = ++i; // a is set to the result of i+1
a = i++; // make a copy of i, compute i+1, save the copy of i in a
Without optimizations, the assembly code would look like this:
a = ++i; a = i++;
MOV eax, (i) MOV eax, (i)
PUSH eax
ADD eax, 1 ADD eax, 1
MOV (i), eax MOV (i), eax
POP eax
MOV (a), eax MOV (a), eax
Now, with optimizations, the result is the same in C where the ++
operator only applies to integers and pointers.
The ++
and --
are there because most processors had an INC
and a DEC
instruction at the time C was written. So if you were to use an index register, these instructions would be applied:
char a[256];
...init 'a' in some way...
int sum =0;
for(int i = 0; i < 100; ++i)
{
sum += a[i];
}
This could be done with a simple INC
as in (6502):
LDA #00
LDY #00
LOOP:
CLC
ADC ($80),Y
INY <-- ++i or i++
CPY #100
BCC LOOP
Note that in C we have another notation to increment a variable:
i += 1;
This is practical if you need to increment the register by more than 1:
i += 3;
Or to double the register each time:
i += i; // (equivalent to i *= 2; or i <<= 1; in C++)
Question: Why is INC
and DEC
not used with all 80x86?
There has been time when the ADD reg, 1
and SUB reg, 1
instructions were faster than the INC reg
and DEC reg
. In the old days, it was faster because the instruction was smaller and we had no cache (or very little). Today, either instruction is probably about the same.
From a comment below, a reason for the "slowness" was the FLAGS register:
Intel Optimization Reference, section 3.5.1.1 Use of the INC and DEC Instructions
From another, more current comment, it looks like the slowness referenced in that Intel document has been fixed in newer processors. So the use or non-use of these instructions should depend on the target processor if known in advance.
As pointed out by phresnel in a comment, the difference between i++
and ++i
was probably not clear for many people. For an integer, the optimization is really trivial and will most certainly happen even with -O0. However, in C++, that's a different story. There is a class with both increment operators clearly showing that a copy is required for i++
(even if data_
is just an integer, although in that case you could also do: return data_++
-- it still requires a well hidden copy!):
class A
{
public:
A& operator ++ () // ++i -- no copy
{
...apply the ++ operation to 'data_'...
return *this; // return a reference to this
}
A operator ++ (int) // i++ -- needs a temporary copy
{
// remember that the 'int' is totally ignored in the function,
// its only purpose is to distinguish '++i' from 'i++'
A copy = *this; // here we need a copy
++*this;
return copy; // and here we return said copy
}
private:
some_type_t data_;
};
Note that modern C++ compilers do not make two copies in the i++
function as the returned value can be optimized out without the need of an extra copy.
The difference between both cases can be shown as clearly slower if using i++
as described in Is there a performance difference between i++ and ++i in C++? (link mentioned by phresnel)
link
for higher performance involve two steps ofADD
&Assignment
. Yes,Assignment
can be a time consumption but in this case it wouldn't matter because the variable to be assigned withi + 1
is already available in the register. So, thewrite allocate
doesn't result in performance damage. – Stockholder++i
, which has decidedly different sequencing characteristics thani++
, but the same expression value asi=i+1
. I suspect things would be considerably different had you used them as rvalues, and the optimizer detecting they were not used as-such was given the green light to reduce them both to++i
. I would expect it in the latter, but you should only see it with the former if it is not used as an rvalue. – Fun