C musing of the day: i++ or ++i?

Here’s another short side-musing about C…

At my previous job, I did embedded programming on TI MSP430, PowerPC and Renesas processors. We were in the process of moving to a new system based on ARM architecture. It was during this time that I went from being part of a tiny local team to being part a much larger group spread out around the world.

But I digress.

On this team were some great minds, and one of them produced a document listing a bunch of optimizations we could do in our code to reduce size and/or improve speed. I wish I had a copy of it as it would be fun to discuss the suggestions here and get some feedback. But for today, I’ll bring up one that was just brought up by a coworker at my current job.

var++ versus ++var

I am very used to writing (and seeing) variable increments written like this:

i++;

Is it called a post increment, I believe. There is another version called pre-increment that looks like this:

++i;

By themselves, the result appears the same. For example:

int i;

i = 0;
printf("i = %d\n", i);
i++;
printf("i = %d\n", i);

That would print 0, then i++ would increment it, then it would print 1.

int i;

i = 0;
printf("i = %d\n", i);
++i;
printf("i = %d\n", i);

That would print 0, then ++i would increment it, then it would print 1.

The reason there is pre and post is for situations where you want to check something at the same time you increment it. If you use “i++” in a check…

i = 0;
if (i++ == 1) printf("This will NOT be printed.\n");

…it checks the value of “i” , then increments it after the check (post increment, see?). But if you go the other way:

i = 0;
if (++i == 1) printf("This WILL be printed.\n");

…it increments “i” first, then checks the new value of i.

Behind the scenes, “i++” has to do more work since it has to retain the original value of i for the compare. I think a post-increment might look something like this:

i = 0;    // SET i TO 0
if (
    i++   // SAVE VALUE OF i AS TEMP_i
          // INCREMENT i
    == 1) // COMPARE TEMP_i TO 1

And a pre-increment might look like this:

i = 0;    // SET i TO 0
if (
    ++i   // INCREMENT i
    == 1) // COMPARE i TO 1

If all you are JUST wanting to increment (or decrement) a variable, it might make sense to always use the pre-increment version (“++i”) so the extra “save this value for later” code is not produced.

BUT, a good compiler optimizer should be able to see that nothing cares about that temporary value and just discard it rather than building it in to your binary.

With a good optimizer, it shouldn’t make any difference. But perhaps it’s better to write it like you mean it since “if (i++ …” means something different than “if (++i …”.

But geez, after twenty years of writing “i++” it sure would be hard to switch.

Does it matter? What if I am writing for an old pre-ANSI K&R compiler?

Comments appreciated.

6 thoughts on “C musing of the day: i++ or ++i?

  1. William Astle

    For any semi-modern compiler, it shouldn’t matter if even basic optimizations are enabled. I would be surprised if gcc, for instance, generates different code between the standalone pre/post increment cases. In fact, I just tested it with gcc6809 with no optimization turned on and both generated identical code which means there’s really no reason to prefer “++i;” over “i++;”.

    Older compilers or even just those with weaker or no optimization might well generate better code with the pre-increment on its own, especially if they don’t do any dead expression elimination, etc. I wouldn’t be surprised to see a special case in many parsers looking for expressions that are just a pre/post increment/decrement and handling them identically. (I suspect something like that in the gcc parser, actually.)

    Basically, a lot of the “old wisdom” about what generates “better” code was probably obselete even by the time it was formulated, or is architecture, compiler, or situation specific.

    As a side note, I suspect the C specification allows the increment in the post increment case to be delayed until the variable is referenced again or the expression ends so depending on context, you might find the increment happening at a surprising time if you look at the generated code. Last I checked, there was a lot of “undefined” behaviour around the incremement/decrement operators in the specification. (Indeed, there’s a lot of stuff that seems perfectly logical that’s actually undefined.)

    Reply
      1. James Jones

        Speaking of which, when the new compiler came out, we were contacted by someone about a bug in it. He was not getting the result he used to get for a statement that was effectively “a[I] = I++;”, the very example in K&R of what you should NOT do. He considered it a massive imposition to have to go find and change all such constructs, and said he planned to stay with the old compiler.

        Reply
  2. James Jones

    I can tell you what Ultra C does. i++ gets turned into something that can get you the value of I and associates a “deferral” with it that has the effect of doing the increment after you are done with I. That happens regardless of optimization level so there’s no reason to choose “++I;” over “I++;”.

    Now objects in C++ are a different matter, and you’re urged never to use postincrement unless you really need to.

    Reply
  3. DuLac (alias factor-h)

    Though I do not like ‘Crickeries’ (the trickeries of C)
    ++ is a valuable tool to reduce pseudocode size (and code too).

    How it works depends on implementation, but one thing is clear:
    There’s no temp copy, except when temp copies is used.
    And that is inside ( ) … thus the presence of two references:
    – The actual variable and the local ( ) value.

    And that should happen both as prefix as a suffix.
    The real reason to use the prefix for efficient code might another:
    var++ … To be legible (believe it or not, that may matter a lot!)
    ++var … The increment may never be used (if repeated it may matter, maybe a lot)

    Anyway, these are opposed. Would say that is quite fair.
    I do not use C … But use ++ in every pseudocode.
    It’s extremely valuable.

    Reply
  4. James Jones

    Oh, yeah… one nice thing that Algol 68C, the Cambridge Algol 68 compiler, did was provide what they called the “displacement operator”, :=:=. (:= was the “becomes operator”, so you would read the expression i := 5 as “i becomes 5”). I believe that i := j :=:= 5 had the effect of assigning 5 to j and assigning what j was before it was assigned 5 to i.

    Just as there was +:= (“plus and becomes”) etc. (whence C got =+ etc. which, thank goodness, became += by K&R 1st edition), there was also +:=:= (“plus and displaces”) etc. C’s i++ is Algol 68C’s i +:=:= 1. For whatever reason, the designers of C decided to only support postincrement and that only by 1. Algol 68C would let you do y := x *:=:= a[n], which would multiply x by a[n] and put the pre-multiply value of x into y.

    Reply

Leave a Reply to James JonesCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.