embedded software boot camp

Efficient C Tips #3 – Avoiding post increment / decrement

Friday, August 1st, 2008 by Nigel Jones

It always seems counter intuitive to me, but post increment / decrement operations in C / C++ often result in inefficient code, particularly when de-referencing pointers. For example

for (i = 0, ptr = buffer; i < 8; i++)
{
 *ptr++ = i;
}

This code snippet contains two post increment operations. With most compilers, you’ll get better code quality by re-writing it like this:

for (i = 0, ptr = buffer; i < 8; ++i)
{
 *ptr = i;
 ++ptr;
}

Why is this you ask? Well, the best explanation I’ve come across to date is this one on the IAR website:

Certainly taking the time to understand what’s going on is worthwhile. However, if it makes your head hurt then just remember to avoid post increment / decrement operations.

Incidentally, you may find that on your particular target it makes no difference. However, this is purely a result of the fact that your target processor directly supports the required addressing modes to make post increments efficient. If you are interested in writing code that is universally efficient, then avoid the use of post increment / decrement.

You may also wonder just how much this saves you. I’ve run some tests on various compilers / targets and have found that this coding style cuts the object code size down from zero to several percent. I’ve never seen it increase the code size. More to the point, in loops, using a pre-increment can save you a load / store operation per increment per loop iteration. These can add up to some serious time savings.

Next Tip
Previous Tip
Home

15 Responses to “Efficient C Tips #3 – Avoiding post increment / decrement”

  1. ashleigh says:

    I've had many long arguments with C programmers who insist that *ptr++ WILL ALWAYS be better / faster / whatever. And I've never come across a case yet where it unambiguously is so.Check the generated code!Avoiding these operators also makes the code much more readable.

  2. Mike Layton says:

    If you read K&R (the original C) you find that they were motivated to make the language as terse as possible–as I recall, to allow transmission at eg. 300 baud. I don't recall hearing a case where terse code is more optimal for space or speed (with or without optimization). Most of the time I'm adding code to insure optimization.

  3. Murray says:

    On GCC with an ARM7tdmi it seems to make no difference at all. However, if you use "uint32_t i;" or "register uint32_t i;" for your local variable declaration, you see a significant size reduction and a speed increase.

  4. MarkM says:

    PowerPC specifically has instructions that support an addressing mode (the “U” instructions) where pre-increment/pre-decrement is provided for free in the load/store instruction itself. There is no equivalent post-increment/post-decrement instruction.

  5. Lundin says:

    I can’t recall a CPU where this would actually matter for efficiency reasons. The real issue here is that *ptr++ may be hard to read. C’s operator precedence rules are far from obvious, and that’s the main reason you should avoid it.

    There’s also the issue with order of evaluation: if you write *ptr++, then you might be tempted to write the classic C bug *ptr = *ptr++, which relies on the implementation-defined order of evaluation (and is banned by MISRA-C). For this reason, professional programmers never use the ++ operator together with other operators ever.

  6. Raul says:

    Hi,

    Thank you for your great articles!

    The link to IAR website is broken. Can you fix it please? Thanks again.

  7. Kyle says:

    Hi,

    The link appears to be broken again! Can you fix it please?

    Thank you for all these great articles and resources!

  8. Kyle says:

    Hi,

    The IAR link appears to be broken again! Can you fix it please?

    Thank you for all these great articles and resources!

  9. Thais says:

    Updated link: https://www.iar.com/knowledge/learn/programming/writing-optimizer-friendly-code/#:~:text=An%20optimizing%20compiler%20tries%20to,on%20a%20sound%20theoretical%20foundation.
    And just in case IAR changes its path again, hereby is the post-increment bit:

    “Try to avoid postincrement and postdecrement
    In the following, everything said about postincrements applies to postdecrements as well. The C standard text for the semantics of postincrement states that “The result of the postfix ++ operator is the value of the operand. After the result is obtained, the value of the operand is incremented”. While it is fairly common that microcontrollers have an addressing mode that can increment a pointer after a load or store operation, very few microcontrollers can handle postincrement of other types with the same efficiency. To comply with the standard the compiler may have to copy the operand to a temporary variable before doing the increment. For straight line code the increment can be lifted out of the expression and placed after the expression. An expression like
    foo = a[i++];
    can be executed as

    foo = a[i];
    i = i + 1;
    But what happens when the postincrement is a part of the condition in a while loop? There is no place after the condition where the increment can be inserted so the increment must be done before the test.

    A simple loop like

    i = 0;
    while (a[i++] != 0)
    {

    }
    has to be executed as

    loop:
    temp = i; /* save the value of the operand */
    i = temp + 1; /* increment the operand */
    if (a[temp] == 0) /* use the saved value */
    goto no_loop;

    goto loop;
    no_loop:
    or

    loop:
    temp = a[i]; /* use the value of the operand */
    i = i + 1; /* increment the operand */
    if (temp == 0)
    goto no_loop;

    goto loop;
    no_loop:
    If the value of i after the loop is irrelevant, it is better to place the increment inside the loop body. The almost identical loop

    i = 0;
    while (a[i] != 0)
    {
    ++i;

    }
    can be executed without temporary variables:

    loop:
    if (a[i] == 0)
    goto no_loop;
    i = i + 1;

    goto loop;
    no_loop:
    Developers of optimizing compilers are well aware of the complexities introduced by postincrements. Even though we try our very best to identify these patterns and eliminate as many of the temporaries as possible, there will always be cases where it is hard to generate efficient code—especially when the loop conditions grow more complex than in the loop above. It is often better to split up a complex expression into several simpler expression, as when the loop condition above was divided into a test and an increment.

    The choice between preincrement and postincrement is even more important in C++. Both operator++ and operator–can be overloaded in both their prefix and postfix forms. When operators are overloaded for class objects it isn’t necessary to emulate the behavior of the operator on the basic types, but it is certainly a good idea to keep the behavior as close to the basic types as possible. So classes where it is intuitive to increment and decrement objects, e.g. iterators, typically have both the prefix (operator++() and operator–()) and the postfix forms (operator++(int) and operator– (int)).

    To emulate the behavior of the prefix ++ for a basic type operator++() can modify the object and return a reference to the modified object. What about emulating the behavior of postfix ++ for a basic type? Do you remember? “The result of the postfix ++ operator is the value of the operand. After the result is obtained, the value of the operand is incremented.” Just as for the non-straight line code above, the implementer of operator++(int) has to copy the original object, modify the original object, and return the copy by value. The copying makes operator++(int) more costly than operator++().

    For the basic types the optimizer can often remove unnecessary copying if the result of i++ is ignored, but the optimizer cannot change a call to one overloaded operator into another. If you, out of habit, write i++ instead of ++i you will call the more costly increment operator.

    We have been arguing against the use of postincrement, but we have to admit that there are times when postincrement is useful. If postincrementing a variable would do exactly what you want to do, go ahead, use postincrement. But don’t postincrement a variable in an expression just to avoid writing a separate expression to increment the variable. Every time you add an unnecessary postincrement to a loop condition, an if condition, a switch expression, a ?:-expression, or function call arguments, there is a possibility that the compiler has to generate larger and slower code. Was that list too long to remember? Start a new habit today! Write ++i instead of i++ when you don’t use the result of the incrementation. When you do use the result, ask yourself if you can’t do the increment as the next statement.”

Leave a Reply

You must be logged in to post a comment.