سؤال

I'm working through K&R and am presently on Exercise 1-16. It occurs to me that thus far only pre-increment has been used in the book.

Most other tutorial books and indeed source code I've seen tend to favour post-increment, except where there is an obvious affect such as in while loops etc.

Is this a stylistic or technical consideration on the part of K&R? Or do I just need to be further through the book to get my answer?!

هل كانت مفيدة؟

المحلول 2

There are several aspects to this.

Semantics

The semantics of pre-increment (decrement) and post-increment (decrement) is different. Whereas the former increments a value before the value is used, the latter increments a value after its use. For example

unsigned i;
for (i=0; i<10; i++ /* ++i */ ) { } 

In this case it would not matter whether one uses pre- or post-increment. Which brings me to the second aspect:

Context

Sometimes it does matter whether to use pre- or post-increment, and that depends on the context of the use. Consider the following example:

char *p = "some string";
unsigned len = 0;

// test 1
while ('\0' != *p++) { len++; }

// test 2 (assumes that p points to a non-empty string)
while ('\0' != *++p) { ++len; }

The result of test 1 is the length of the string, the result of test 2 is the length of the string minus one. Because the incremented value p is used as part of an expression, it does matter when the increment happens: after the use of p in the expression (test 1), or before its use (test 2). Because len is not used as part of an expression, it does not matter whether one uses pre- or post-increment.

And that brings me to the third aspect.

Implementation

In order to implement a post-increment, the value of p must be stored away for its later use to increment it, which takes up extra storage space for a temporary value. Pre-increment does not require temporary storage space. Modern optimizing compilers, however, are able to generate the same code for pre- and post-increment, if the incremented value is not used as part of an expression where the temporary value would be needed to evaluate that expression.

Which brings me to the fourth aspect (somewhat hinted at in the previous paragraph), but that is more C++ related.

Performance

In C++ the decrement and increment operators can be overloaded (link) to work with complex types, and STL (link) does make substantial use of that to implement iterators (link) for its container types. In that case, a value like

set::iterator it;

can be a rather complex thing with more than trivial state (i.e. it's not just a primitive integer). In that case, using pre-increment ++it does make a difference over post-increment it++ because there is no need to store a temporary value away like it is needed for post-increment if used in an expression (see Context). And that can save quite some runtime overhead.

نصائح أخرى

About 10 million years ago, before the dawn of optimizing compilers, this used to matter*. It really doesn't anymore. The rationale was that an additional store operation is required in order to implement post-increment in the naive manner. Compilers mostly don't implement it this way though, so just prefer whichever style makes more sense given the context and trust your compiler to do the right thing.

*JimBalter correctly pointed out that this was never a problem, and I should not have suggested that it once might have mattered.

I would say (even if post-increment operator comes first in the Standard because of higher precedence of postfix operators) that pre-increment is the natural way of incrementing the value of an object so that's a good reason to use it if the only thing you want is to increment the value of an object,

(++E) is equivalent to (E+=1) but not (E++)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top