To Prefix or Postfix

Being curious, I asked ChatGPT which C programming questions it gets asked most frequently. Some of the topics are complex, such as back peddling through a linked list. I cover double-linked lists on this blog, though I don’t demonstrate how to work backwards through one.

According to ChatGPT, one of the frequent questions is about the increment and decrement operators, specifically prefixing and postfixing. This topic is more inline with an issue a beginning C programmer would face.

When prefixed, the increment/decrement operators affect the operand (variable) before its value is accessed.

For example, if x is set to zero, ++x sets the value to 1, then the value is used.

If x is set to zero, x++ results in the value zero when x is accessed, but 1 afterwards.

The confusion probably arises from the fact that as a statement by itself it makes no difference whether you use ++x or x++. The result is always going to be one greater than the value of x. But when used in an expression, such as part of a looping condition, the prefix and postfix positions definitely play a role.

The following code runs two while loops. Each outputs values of variable x initialized to zero. The first uses a prefix operator in the looping condition, the second uses a postfix.

2025_03_22-Lesson.c

#include <stdio.h>

int main()
{
    const int count = 10;
    int x;

    /* prefixed */
    x = 0;
    puts("Prefixed: ++x");
    while( ++x<count )
        printf("%d\n",x);

    /* postfixed */
    puts("Postfixed: x++");
    x = 0;
    while( x++<count )
        printf("%d\n",x);

    return 0;
}

As a prefix operator in the first while loop uses the expression (++x<count), the value of x is incremented before the comparison is made with constant count.

When used as a postfix operator in the second while loop (x++<count), the value of x is incremented after the expression is evaluated: It’s compared with variable count, then it’s incremented.

Here is the output:

Prefixed: ++x
1
2
3
4
5
6
7
8
9
Postfixed: x++
1
2
3
4
5
6
7
8
9
10

The first loop outputs nine values, meaning that the loop repeats only nine times, not ten. The second loop outputs ten values. In both cases, the first value output is 1 because variable x is already incremented.

The moral of this story is to always use the postfix operator in a looping expression if you want the loop to repeat the full count. In fact, I see the postfix operator used more often than the prefix operator in this situation. This confusion is probably one of the reasons ChatGPT gets asked this question often. Comparatively, the ++x operation just looks odd.

Because after-loop operations may rely upon the looping variable to be one greater than the count, it’s important to know which operation comes first. For example, when using a loop to process a string, the final looping value can be used to cap the null character on the string.

I’m curious whether any situation exists when the prefix operator is necessary in an expression. It’s available, but I don’t recall seeing any instance where it’s required. As someone who likes to write readable code, I often don’t bunch up operations as was done in this Lesson’s sample code. I prefer to use separate statements to avoid such confusion.

6 thoughts on “To Prefix or Postfix

  1. I realize that this site is an adjunct to the “C for Dummies” books. However, with C++ in mind I usually prefer the prefix increment operator over the postfix one:

    I.e. I usually write for (i=0; i<n; ++i) instead of for (i=0; i<n; i++). For the simple reason that a prefix increment, at least in principle, is a little bit more efficient than a postfix increment.

    Granted, in simple C code this doesnʼt really make any difference, but good habits are hard to form and it might become important if and when operator overloading enters the picture. E.g. in case of a simple class Point in C++:

    class Point
    {
      int _x, _y;
    public:
      Point() { _x = _y = 0; } // Default constructor: Point p;

      // Overloaded operators:
      Point& operator++ (); // Prefix increment: ++p;
      Point operator++ (int); // Postfix increment: p++;
    };

    Point& Point::operator++ () // Prefix increment operator.
    {
      ++_x; // (Admittedly, maybe not the best
      ++_y; // illustration of operator overloading.)
      return (*this);
    }

    Point Point::operator++ (int) // Postfix increment operator.
    {
      Point temp = *this; // save coordinates
      ++_x; // increment coordinates
      ++_y;
      return (temp); // return saved coordinates
    }

  2. From what I read, Ritchie came up with the increment operator – which wasn’t present in the B language – because of a machine level op that did the same thing. If so, how would it be more efficient to prefix? At the machine level, it’s two operations, so why would their order matter?

  3. #include <stdio.h>
    #include <sys/types.h>

    void search_array (int arr []);

    int main (void)
    { int num [] = {1, 1, 2, 5, 8, 13};

      search_array (num);

      return (num [0]);
    }

    void search_array (int arr [])
    {
      ssize_t index = 0;

      do
        ; /* do nothing (NOP) */
      while (arr [index++] != 8);

      printf (“#x22;Found 8 at a (zero-based) index of %d\n”#x22;, index);
    }

    The given loop condition presents the compiler with a problem, as it logically has to do 3 steps:

    ⒈ cmp dword [arr + 4*index], 8 ; compare array element to eight
    ⒉ jne .do ; jump to label .do if not equal
    and then perform an increment operation on ‘index’ (irrespective of the result of the previous jump instruction)

    … it will have to generate code that (logically) performs one additional operation after the loop condition check!

    On x86-64 the GCC compiler solves this by generating the following code if the ‘-O2’ command-line option is given:

    search_array:
    xor esi, esi ; register ESI points to ‘arr[0]’
    .do:
    add rsi, 1 ; already increase loop counter, but then
    cmp word [rdi + 4*rsi – 4], 8 ; go back 4 bytes in memory
    jne .L2

    If the above code is changed so that the loop condition reads while (arr [index++] != 8), the following code is generated instead:

    search_array:
    mov rsi, -1 ; register ESI points to ‘arr[-1]’
    .do:
    add rsi, 1 ; pre-increment ‘index’
    cmp dword [rdi + 4*rsi], 8 ; no ‘- 4’ necessary here.
    jne .L2

    Admittedly, for the run-time of the code it wonʼt make a difference even in this example… but the above illustrates, that ‘pre-increment’ is often (if not always) conceptually a bit simpler than ‘post-increment’.

  4. Just noticed that there is an unfortunate copy paste error in the sentence above the second assembly language fragment:

    If the above code is changed so that the loop condition reads as while (arr [++index] != 8);, the following code is generated instead:

  5. One last addition to this topic: the reverse can also be true sometimes, so the situation is not as clear cut as it might seem if one only looks at the above example.

    As illustrated in this SO answer, a pre-increment can sometimes introduce a data dependency:

    a = ++b * 2;

    Given the above statement, the multiplication “has to wait” until the result of the pre-increment is ready. On the other hand, with a post-increment,

    a = b++ * 2;

    the statements ‘a = b * 2’ and ‘b++’ can potentially run in parallel within the processor.

    All in all it’s probably best to not think too much about such minuscule effects, but one type of increment will sometimes be a teeny-tiny bit more efficient than the other.

Leave a Reply