7

In C and many of its derivatives, i++ increments i and evaluates to the value of i before it was incremented, and ++i increments i and evaluates to the value of i after it was incremented.

I can see the reasoning for a specific increment operator; many processors at the time had a special increment opcode that was faster than addition and conceptually "increment" is a different idea from "add," in theory having them be written differently might make code more readable.

What I don't understand is the need for the pre-increment operator. Can't any practical use for it be written like this?

#This...
x = i++;
#becomes this:
x = i; 
++i;

Is there a historical reason I don't know about, maybe? Were you unable to "throw away" the return values of operators in primordial versions of C?

Shog9
  • 156,901
  • 35
  • 231
  • 235
Schilcote
  • 2,344
  • 1
  • 17
  • 35
  • Can this question be edited to bring it into scope? I will be happy to edit my answer and add some historical context but there's no point my doing any more work on it until the question is taken off hold. I also need to know which increment operators are being addressed (excuse the pun). – Mick Sep 23 '16 at 17:35
  • [This question is being discussed on meta](http://meta.stackoverflow.com/questions/335085/is-it-okay-to-delete-and-re-make-a-question-to-stop-everyone-hyperfocusing-on-a) and after being deleted here has been [re-asked in a clarified form on Programmers](http://programmers.stackexchange.com/questions/331870/origins-of-having-both-prefix-incrementi-and-postfix-increment-i-in-the). For transparency while these discussions are ongoing, I've undeleted it here and will impose a temporary (1-day) lock. – Shog9 Sep 23 '16 at 21:16

2 Answers2

12

One reason is that it allowed for the generation of efficient code without having any fancy optimisation phases in compilers, provided that the programmer knew what he (or she) was doing. For example, when copying characters from one buffer to another, you might have:

register char *ptr1;
register char *ptr2;
...
for ( ... ) {
    *ptr1++ = *ptr2++; /* post-increment */
}

A compiler that I once worked with (on a proprietary minicomputer) would generate the following register operations for the assignment:

load  $r1,*$a1++       // load $r1 from address in $a1 and increment $a1
store $r1,*$a2++       // store $r1 at address in $a2 and increment $a2

I forget the actual opcodes. The compiler contained no optimisation phase yet the code that it generated was very tight providing that you understood the compiler and the machine architecture. It could do this because the hardware architecture had pre-decrement and post-increment addressing modes for both address registers and general registers. There were no pre-increment and post-decrement addressing modes as far as I recall but you could get by without those.

I believe that the DEC minicomputers on which C was originally developed had such addressing modes. The machine that I worked on wasn't made by DEC but the architecture was pretty similar.

An optimisation phase was planned for the compiler. However, it was mostly used by systems programmers and when they saw how good the generated code was, implementation of the optimisation phase was quietly shelved.

The whole rationale for the design of C was to allow the creation of simple and portable compilers that would generate reasonably efficient code with minimal (or no) intermediate code optimisation. For this reason, the increment and decrement operators and also the compound assignment operators played an important role in the generation of compact and efficient code by the early C compilers. They were not just syntactic sugar as suggested by Niklaus Wirth et al.

Mick
  • 4,987
  • 1
  • 19
  • 23
-2

So you can, for example, do this

While (++i < threshold) [do something];

and this...

While (i++ < threshold) [do something];

or any of a thousand other specific implementations that both use the value and increment it in a single statement and get the expected different results

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • That seems awfully specific though. Are you sure that's the actual historical reason? – Schilcote Sep 23 '16 at 02:01
  • There is no historical reason - they have different purposes. – NonCreature0714 Sep 23 '16 at 02:03
  • These are actually interesting variants. with ++i < threshold. After the loop is done, the value is one beyond the last processed index, i. With i++ it is two beyond. ++i is better for a while loop, since max valid index +1 is processed with i++. Look at all iterations of (i++ < 2) compared to (++i < 2) to see the distinction. But, a[++i] = b[i] is a confusing construct... – BenPen Sep 23 '16 at 17:29
  • @BenPen, I don't see what you're getting at. Whether you increment before, or after, there is always still only one increment. The issue is what you are thresholding on, Do you want all values up to and including the threshold, or only those less than the threshold... – Charles Bretana Sep 23 '16 at 17:34
  • Consider i = 0; while (i++ < 1) { do_it(i) } That actually executes a loop iteration for i==1 but not i==0, not what you'd intended probably, since the loop condition is evaluated, then i is incremented, THEN do_it(i) is executed with the new value for i. – BenPen Sep 23 '16 at 17:39
  • My original comment was a bit off, yes, but the two constructs are different in troublesome ways. while(i++ < 1) has non-intuitive behavior, who would expect that i==1 is the only iteration executed, when the "invariant" is i<1. – BenPen Sep 23 '16 at 18:00
  • Yes, this is true, yet I use it when I want to initialize a `cntr` with 0, use the `cntr` as index into a list, but I want body of loop to iterate over`cntr` values between 1 and the count of items for some log entry or message construction. – Charles Bretana Sep 23 '16 at 21:37