Sign In
Forgot Password?
Sign In | | Create Account

++i or i++?

Colin Walls

Colin Walls

Posted Aug 10, 2009
5 Comments

If you are reading this blog, you are probably knowledgeable about embedded software and, therefore, like me, you consider yourself proficient in C. C is still the dominant language for embedded work. I read an article recently which espoused the view that “real men program in C” – I rather liked that. It also suggested that, since relatively few new graduates know C, there is an increasing shortage of expertise. This is great news for us old hands.

However, we should not be complacent. I think that I know C quite well. After all, it is quite a small language, so getting a grip should not be hard. Even aspects of it that are specifically interesting to embedded developers [and there are quite a few] should not be too difficult to master. But sometimes it is possible to get caught out …

I will pose a question: what is the difference between ++i and i++?
I am sure that you know that both expressions result in the variable i being incremented, but the first expression yields the incremented value if i, whereas the second returns the value prior to incrementing. OK so far. But what if the expression result is discarded in a situation like this, for example:

for (i=0; i<5; i++)

Does it make any difference which form of the increment operator is used in this context? I would have said no. But then I had a conversation with one of our compiler team and now I know better.

Functionally, it makes no difference – ++i and i++ would both do the right thing. However, 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.

If you have any other examples of subtle C features that are interesting to embedded developers, please email me.

More Blog Posts

About Colin Walls Follow on Twitter

Colin WallsI have over twenty-five years experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles and two books on embedded software, I am a member of the marketing team of the Mentor Graphics Embedded Systems Division, and am based in the UK. Away from work, I have a wide range of interests including photography and trying to point my two daughters in the right direction in life. Learn more about Colin, including his go-to karaoke song and the best parts of being British: http://go.mentor.com/3_acv Visit The Colin Walls Blog

More Posts by Colin Walls

Comments 5

Post a Comment
This very discussion arises quite regularly in code reviews in my company. Next time I'll just forward a link to this article and save my blood pressure :)

Stephen Doyle
9:30 PM Aug 10, 2009

Stephen: Good to hear that this is recognized in the "real world". If you have any other issues that might be worth my discussing here, please email me: colin_walls@mentor.com

Colin Walls
9:33 PM Aug 10, 2009

There's also the possibility of actually having an assembly operator that makes more sense with one operation or the other. For example, out of my head I can think of DBCL (decrement and branch if clear). A good compiler would turn --i into that single instruction. I don't think I can recall right now an instruction set that has that instruction in an increment version so I usually try to do for or while loops with predecrement, but there are indexing modes with post-increment that would make sense in other places. Anyway, it's always good to also consider how what you are writing will translate into assembly. By the way, that article has created so much hype that I'm also considering blogging about it.

Eduardo
2:48 AM Aug 11, 2009

Good input Eduardo. It raised a thought in my mind: If you want to go around a loop say 10 times and you don't care about the direction of loop counting, doing it from 10 to 0 would be better, as the detection of zero is always easier than a comparison.

Colin Walls
8:07 AM Aug 11, 2009

*** 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 believe that any reasonable C compiler since PCC (1974) will optimize this away. I was writing C compilers on three occasions and I cannot imagine a compiler company that would not optimize away i++ or even a->b[c].d.e->f ++. It will not be optimized away if the value of the expression is used: a = b++, which is reasonable. Maybe some compilers will have problems with expressions with side effects, like this: a[f ()]++ or some compilers may have special semantics for "volatile" objects. But other then this I don't see much point in this discussion - IMHO anybody can safely assume that ((void) i++) alone is equivalent to ((void) ++i). Yuri Panchul

Yuri Panchul
4:36 PM Aug 11, 2009

Add Your Comment

Please complete the following information to comment or sign in.

(Your email will not be published)

Archives

 
Online Chat