Search

Enter your search terms

Submit search form

3.3 — Increment/decrement operators, and side effects

By Alex on June 13th, 2007 | last modified by Alex on July 29th, 2017

Incrementing (adding 1 to) and decrementing (subtracting 1 from) a variable are so common that they have their own operators in C. There are actually two versions of each operator -- a prefix version and a postfix version.

Operator

Symbol

Form

Operation

Prefix increment (pre-increment)

++

++x

Increment x, then evaluate x

Prefix decrement (pre-decrement)

––

––x

Decrement x, then evaluate x

Postfix increment (post-increment)

++

x++

Evaluate x, then increment x

Postfix decrement (post-decrement)

––

x––

Evaluate x, then decrement x

The prefix increment/decrement operators are very straightforward. The value of x is incremented or decremented, and then x is evaluated. For example:

1

2

intx=5;

inty=++x;// x is now equal to 6, and 6 is assigned to y

The postfix increment/decrement operators are a little more tricky. The compiler makes a temporary copy of x, increments or decrements the original x (not the copy), and then evaluates the temporary copy of x. The temporary copy of x is then discarded.

1

2

intx=5;

inty=x++;// 5 is assigned to y, and x is now equal to 6

Let’s examine how this last line works in more detail. First, the compiler makes a temporary copy of x that starts with the same value as x (5). Then it increments the original x from 5 to 6. Then the compiler evaluates the temporary copy, which evaluates to 5, and assigns that value to y. Then the temporary copy is discarded.

Consequently, y ends up with the value of 5, and x ends up with the value 6.

Here is another example showing the difference between the prefix and postfix versions:

1

2

3

4

5

6

intx=5,y=5;

cout<<x<<" "<<y<<endl;

cout<<++x<<" "<<--y<<endl;// prefix

cout<<x<<" "<<y<<endl;

cout<<x++<<" "<<y--<<endl;// postfix

cout<<x<<" "<<y<<endl;

This produces the output:

5 5
6 4
6 4
6 4
7 3

On the third line, x and y are incremented/decremented before they are evaluated, so their new values are printed by cout. On the fifth line, a temporary copy of the original values (x=6, y=4) is sent to cout, and then the original x and y are incremented. That is why the changes from the postfix operators don’t show up until the next line.

Rule: Favor pre-increment and pre-decrement over post-increment and post-decrement. The prefix versions are not only more performant, you’re less likely to run into strange issues with them.

Side effects

A function or expression is said to have a side effect if it modifies some state (e.g. any stored information in memory), does input or output, or calls other functions that have side effects.

Most of the time, side effects are useful:

1

2

3

x=5;

++x;

std::cout<<x;

The assignment operator in the above example has the side effect of changing the value of x permanently. Even after the statement has finished executing, x will have the value 5. Operator++ has the side effect of incrementing x. The outputting of x has the side effect of modifying the console.

However, side effects can also lead to unexpected results:

1

2

3

4

5

6

7

8

9

10

11

12

13

intadd(intx,inty)

{

returnx+y;

}

intmain()

{

intx=5;

intvalue=add(x,++x);// is this 5 + 6, or 6 + 6? It depends on what order your compiler evaluates the function arguments in

std::cout<<value;// value could be 11 or 12, depending on how the above line evaluates!

return0;

}

C++ does not define the order in which function arguments are evaluated. If the left argument is evaluated first, this becomes a call to add(5, 6), which equals 11. If the right argument is evaluated first, this becomes a call to add(6, 6), which equals 12! Note that this is only a problem because one of the argument to function add() has a side effect.

Here’s another popular example:

1

2

3

4

5

6

7

8

intmain()

{

intx=1;

x=x++;

std::cout<<x;

return0;

}

What value does this program print? The answer is: it’s undefined.

If the ++ is applied to x before the assignment, the answer will be 1 (postfix operator++ increments x from 1 to 2, but it evaluates to 1, so the expression becomes x = 1).

If the ++ is applied to x after the assignment, the answer will be 2 (this evaluates as x = x, then postfix operator++ is applied, incrementing x from 1 to 2).

There are other cases where C++ does not specify the order in which certain things are evaluated, so different compilers will make different assumptions. Even when C++ does make it clear how things should be evaluated, some compilers implement behaviors involving variables with side-effects incorrectly. These problems can generally all be avoided by ensuring that any variable that has a side-effect applied is used no more than once in a given statement.

Rule: Don’t use a variable that has a side effect applied to it more than once in a given statement. If you do, the result may be undefined.

Please don’t ask why your programs that violate the above rule produce results that don’t seem to make sense. That’s what happens when you write programs that have “undefined behavior”. 🙂

Share this:

121 comments to 3.3 — Increment/decrement operators, and side effects

Hi Alex,
I wanted to check whether my compiler evaluates the left or right argument first, using the code you provided in this lesson. In theory, one of the two values should have been 11 and the other 12, no? In fact both return 12. Am I understanding things incorrectly here?

You're seeing unexpected results because you're breaking one of the most broken rules in C++: Don't use a variable with side effects applied more than once in an expression. Operator++ applies a side effect, so you're running afoul of this rule, and the result you're seeing is the result of undefined behavior.

Here's a program I whipped up that will tell you your evaluation order:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#include <iostream>

intgen()

{

staticintx=10;

return--x;

}

voidleftRight(intleft,intright)

{

if(left<right)

std::cout<<"right got evaluated first\n";

else

std::cout<<"left got evaluated first\n";

}

intmain()

{

leftRight(gen(),gen());

return0;

}

gen() returns 9 the first time it's called, and 8 the second time. By looking whether left is 8 and right is 9 or vice-versa, we can determine which operand got evaluated first.

Thanks! And apologies for forcing you to repeat the same thing again.
I thought I was not using it twice in an argument actually as I was using the operator only once. I guess it's the variable that I should count and not how many times I am using the operator.

No. The higher precedence means x++ is evaluated first. That evaluation means x++ will be evaluated to produce the value x. The actual increment part is not guaranteed to happen immediately (think of post-increment as "increment at some point in the future"). So it could be the assignment happens first, or the ++ happens first.

This was probably originally done for performance reasons, but is one of those annoying quirks of the language that you have to learn not to do.

In this e.g., I understand in this way "First, a memory location x with value 5 is made a temporary copy with temp copy which has value 5. Then 'Evaluate x' means 'assign value of temp copy 5 to y', discard temp copy, incrementing x from 5 to 6."

So with same token,

int x = 5;
++x++; //This evaluates to ++(x++) due to postfix has higher precedence than prefix
So on the postfix x++, it will Evaluate x, then increment x.

In this case, "First, a memory location x with value 5 is made a temporary copy with temp copy which has value 5(now has two memory locations with value 5). Then 'Evaluate x' means 'working on ++x' which would evaluate to temporary copy increased to 6 then discard temporary copy, then incrementing original x from 5 to 6.

Somehow, my understanding lacks of incorporation of r-value and l-value concept inside and so it seems compiler should compile though I think something is amiss.

Don't worry about r-values and l-values in this context. int x = 5 is just memory location x being initialized with value 5. x++ evaluates to 5 means that the compiler reduces that expression to the singular value 5. So even though x is incremented to 6 (as a side effect), the value 5 is assigned to y, since that's what x++ evaluated to.

Hi Alex. Can you please explain this program. This is the same program given in example in this chapter but I made a change in the line where the add function is called. I added pre-decrement operator. When I executed your example without any change, the output was 12, which means that my compiler (code blocks) first operates on the right argument. If it is so, then this program should have given 11 as output but the output given is 10.

Hi! Great tutorials!
I have a bit of a question...
I wrote a code that finds the prime numbers up to 100. It works fine, but I can't figure it out how to deal with the first prime number, witch is 2.
I put there a separate if statement, just to output 2, and after that it goes normal for the rest of the numbers.
But I would like to make the code more generic, without working separately just for 2.

From the Table in section 3.1 we find the precedence and the associativity for the post-increment (x++) and the array subscript operators [], respectively

2 L->R ++ Post-increment (x++)
2 L->R [] Array subscript

They have the same precedence level 2, and the same associativity L->R. How is the rule applied now? It's not evaluated L->R, more from inside and out, how does the compiler read the code array[x++] (what rules are applied)?

Just a note, the pre-increment operator (++x) has a lower order of precedence, and associative R->L, i.e.

In the post-increment case, the subscript operator is evaluated first (because it's to the left of the postfix-++), and a function named operator[] is called with x++ as a parameter. At this point, x++ gets evaluated to the value of x, which is passed into operator[], which uses that value to subscript the array.

It works the same way in the pre-increment case, except ++x evaluates to x+1, which is the value that gets passed into the subscript function and used to subscript the array.

I don't see the problem in the last one, I mean, if ++ is evaluated first then x will be 2 and then the = will be evaluated which will make x be 2. If the = is evaluated first x = x which is one, and then the ++ will be evaluated which will cause x to be 2, right? I guess I'm doing it wrong in some part, but I don't know how.

Not quite sure what you're asking. Question 1 and 2 are bad practice because you're using a variable with a side effect applied more than once in an expression (x = x++). Question 3 is fine though, because you're not violating this rule.

What value does this program print? The answer is: it’s undefined. If the ++ is applied to x before the assignment, the answer will be 1. If the ++ is applied to x after the assignment, the answer will be 2.

Unfortunately, the answer is somewhat complicated, and has to do with something called sequence points. A sequence point is a point in the program where it's guaranteed that all side effects from previous evaluations have been performed. Between sequence points, the order of side effects resolution is indeterminate.

The challenge with this particular program is that the side effects from postfix operator++ and the assignment operator aren't separated by a sequence point, so the compiler is free to apply those side effects in either order.

If the ++ is applied after the assignment: First x++ evaluates to 1. That 1 is assigned to x. Then the ++ is applied to x, which increments it to 2.
If the ++ is applied to x before the assignment: First x++ evaluates to 1. The ++ is then applied, changing the value of x to 2. The value of 1 from the previous evaluation is then assigned to x, leaving x with the final value of 1.

Both of these are valid interpretations of how to resolve the expression in C++, and different compilers may choose to do it differently.