EmbeddedRelated.com
Blogs
Memfault Beyond the Launch

++i and i++ : what’s the difference?

Colin WallsJanuary 25, 20242 comments

A facet of the C language that has always appealed to me is its size - it is not a complex sprawling language. A thorough understanding of it can be gleaned quite quickly and many programmers actually use a very significant proportion of the language. Using it well is a challenge. The important thing is to write clear, understandable, maintainable code. Efficiency is very important for many embedded applications and, even though a modern compiler will do much of the heavy lifting, understanding some of the underlying implementation details can be very beneficial. This is what I want to think about today.

I want to talk about the humble ++ operator. Everything I have to say also applies to the -- as well - I am not being polarityist! Almost any C programmer would claim, not unreasonably, that they thoroughly understand this operator and know exactly how to use it. Be that as it may, I want to quickly summarize its operation before exploring some lesser-known facets of its implementation.

So, the ++ operator simply increments - adds 1 to - the variable to which it applies. That is easy to understand and in many cases this is the end of the story. However, there are two forms of the ++ operator: pre-increment and post-increment. Here is an illustration of their operation:

This article is available in PDF format for easy printing
x = 3;
y = 3;
z = ++x; // x and z are both 4
z = y++; // y is 4 and z is 3

The two variants of the operator have the same effect on the variable to which they are applied, but the value of the expression is evaluated differently; one returns the value of the variable before incrementing, the other returns the value after incrementing. If the expression is simply converted to a statement - by adding a semicolon - the expression value is discarded, so either operator could be used, thus:

x = 3;
y = 3;
++x;
y++; // x and y are both 4

It might be concluded that the operators are interchangeable in this context, but, as we shall see, this may not always be the case.

Before going on to see why the two operator variants may not be truly interchangeable, I want to explore another aspect of how they work that some developers find confusing.

Most of the time, the word “increment” means “add one”, but this is not necessarily the case with the ++ operator. Consider this code:

unsigned *p;
p = (unsigned *)0x80000000;
p++;

The pointer p is set to point to the memory location at address 0x80000000, then it is incremented. What value does it have now? The answer is 0x80000004. In a way, this is obvious, as, if this were an array of 32-bit unsigned variables, the address of the next one would be 0x80000004. This works because, in C, a pointer is not simply an address; the size of the data type to which it points is also known and applied when arithmetic is performed on pointers. I will leave as an exercise the problem of how you might persuade the ++ operator to increment p by one to yield 0x80000001.

Now back to the main issue: how do the two variants of the increment operator vary when used alone in a statement and does your choice matter?

We know that functionally the two operators are equivalent, but we need to think about the implementation by the compiler of the increment operators. Embedded developers are interested in more than just functionality – we are always interested in overheads. Think about what code might be compiled for each form of the expression. For ++i, the variable is simply incremented; for i++, the value needs to be stored somewhere and then the variable is incremented. This means that the post increment form needs some additional storage, which is an unwanted overhead.

Of course, for a simple integer, the overhead is quite small. But, if the variable were actually a complex C++ object, it might be a more serious matter.

It can be argued that a good compiler would observe that the expression result is not needed and this code would be optimized away. I sincerely hope that this would be the case. However, it is sloppy programming to just rely on compiler optimization to address the ignorance or laziness of the programmer.

So, a good rule is to use the pre-increment form - ++i - by default. Only use the post-increment variant when that is specifically needed.



Memfault Beyond the Launch
[ - ]
Comment by jacobqFebruary 1, 2024

While I don't disagree, I would argue that, rather than have to worry about pre/post operation, a better "good rule" might be to avoid incrementing/decrementing a variable and using it for other purposes in the same statement.

[ - ]
Comment by colinwallsFebruary 1, 2024

I think, on balance, I agree, as I prefer a sequence of simple or very simple statements to a single, long, complex one - my C often looks like assembly language.

To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.

Please login (on the right) if you already have an account on this platform.

Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: