Reputation: 375
What is the necessity of both prefix and postfix increment operators? Is not one enough?
To the point, there exists like a similar while/do-while necessity problem, yet, there is not so much confusion (in understanding and usage) in having them both. But with having both prefix and postfix (like priority of these operators, their association, usage, working). And do anyone been through a situation where you said "Hey, I am going to use postfix increment. Its useful here."
Upvotes: 6
Views: 2760
Reputation: 214495
As for any other obscure mechanism in the C language, there are various historical reasons for it. In ancient times when dinosaurs walked the earth, compilers would make more efficient code out of i++
than i+=1
. In some cases, compilers would generate less efficient code for i++
than for ++i
, because i++
needed to save away the value to increment later. Unless you have a dinosaur compiler, none of this matters the slightest in terms of efficiency.
As for any other obscure mechanism in the C language, if it exists, people will start to use it. I'll use the common expression *p++
as an example (it means: p
is a pointer, take the contents of p
, use that as the result of the expression, then increment the pointer). It must use postfix and never prefix, or it would mean something completely different.
Some dinosaur once started writing needlessly complex expressions such as the *p++
and because they did, it has became common and today we regard such code as something trivial. Not because it is, but because we are so used at reading it.
But in modern programming, there is absolutely no reason to ever write *p++
. For example, if we look at the implementation of the memcpy
function, which has these prerequisites:
void* memcpy (void* restrict s1, const void* restrict s2, size_t n)
{
uint8_t* p1 = (uint8_t*)s1;
const uint8_t* p2 = (const uint8_t*)s2;
Then one popular way to implement the actual copying is:
while(n--)
{
*p1++ = *p2++;
}
Now some people will cheer, because we used so few lines of code. But few lines of code is not necessarily a measure of good code. Often it is the opposite: consider replacing it with a single line while(n--)*p1++=*p2++;
and you see why this is true.
I don't think either case is very readable, you have to be a somewhat experienced C programmer to grasp it without scratching your head for five minutes. And you could write the same code like this:
while(n != 0)
{
*p1 = *p2;
p1++;
p2++;
n--;
}
Far clearer, and most importantly it yields exactly the same machine code as the first example.
And now see what happened: because we decided not to write obscure code with lots of operands in one expression, we might as well have used ++p1
and ++p2
. It would give the same machine code. Prefix or postfix does not matter. But in the first example with obscure code, *++p1 = *++p2
would have completely changed the meaning.
To sum it up:
You can use this as a quality measure of your code: if you ever find yourself writing code where it matters whether you are using prefix or postfix, you are writing bad code. Stop it, rewrite the code.
Upvotes: 1
Reputation: 11070
POSTFIX and PREFIX are not the same. POSTFIX increments/decrements only after the current statement/instruction is over. Whereas PREFIX increments/decrements and then executes the current step. Example, To run a loop n times,
while(n--)
{ }
works perfectly. But,
while(--n)
{
}
will run only n-1 times
Or for example:
x = n--;
different then x = --n;
(in second form value of x
and n
will be same). Off-course we can do same thing with binary operator -
in multiple steps.
Point is suppose if there is only post --
then we have to write x = --n
in two steps.
There can be other better reasons, But this is one I suppose a benefit to keep both prefix and postfix operator.
Upvotes: 5
Reputation: 21645
You don't need both.
It is useful for implementing a stack, so it exists in some machine languages. From there it has been inherited indirectly to C (In which this redundancy is still somewhat useful, and some C programmers seems to like the idea of combining two unrelated operations in a single expression), and from C to any other C-like lagnuages.
Upvotes: 0
Reputation: 154075
[edit to answer OP's first part]
Clearly i++
and ++i
both affect i
the same but return different values. The operations are different. Thus much code takes advantage of these differences.
The most obvious need to have both operators is the 40 year code base for C. Once a feature in a language is used extensively, very difficult to remove.
Certainly a new language could be defined with only one or none. But will it play in Peoria? We could get rid of the -
operator too, just use a + -b
, but I think it is a tough sell.
Need both?
The prefix operator is easy to mimic with alternate code for ++i
is pretty much the same as i += 1
. Other than operator precedence, which parens solves, I see no difference.
The postfix operator is cumbersome to mimic - as in this failed attempt if(i++)
vs. if(i += 1)
.
If C of the future moved to depreciate one of these, I suspect it would be to depreciate the prefix operator for its functionality, as discussed above, is easier to replace.
Forward looking thought: the >> and << operators were appropriated in C++ to do something quite different from integer bit shifting. Maybe the ++pre and post++ will generate expanded meaning in another language.
[Original follows]
Answer to the trailing OP question "do anyone been through a situation where you saidd "Hey, I am going to use postfix increment. Its useful here"?
Various array processing, like with char[], benefit. Array indexing, starting at 0, lends itself to a postfix increment. For after fetching/setting the array element, the only thing to do with the index before the next array access is to increment the index. Might as well do so immediately.
With prefix increment, one may need to have one type of fetch for the 0th element and another type of fetch for the rest.
size_t j = 0;
for (size_t i = 0, (ch = inbuffer[i]) != '\0'; i++) {
if (condition(ch)) {
outbuffer[j++] = ch; // prefer this over below
}
}
outbuffer[j] = '\0';
vs.
for (size_t i = 0, (ch = inbuffer[i]) != '\0'; ++i) {
if (condition(ch)) {
outbuffer[j] = ch;
++j;
}
}
outbuffer[j] = '\0';
Upvotes: 3
Reputation: 123558
Here's a quickie example that uses both; an array-based stack, where the stack grows towards 0:
#define STACKSIZE ...
typedef ... T;
T stack[STACKSIZE];
size_t stackptr = STACKSIZE;
// push operation
if ( stackptr )
stack[ --stackptr ] = value;
// pop operation
if ( stackptr < STACKSIZE )
value = stack[ stackptr++ ];
Now we could accomplish the exact same thing without the ++ and -- operators, but it wouldn't scan as cleanly.
Upvotes: 1
Reputation: 14714
They are necessary because they are already used in lots of code, so if they were removed then lots of code would fail to compile.
As to why they ever existed in the first place, older compilers could generate more efficient code for ++i
and i++
than they could for i+=1
and (i+=1)-1
. For newer compilers this is generally not an issue.
The postfix version is something of an anomaly, as nowhere else in C is there an operator that modifies its operand but evaluates to the prior value of its operand.
One could certainly get by using only one or other of prefix or postfix increment operators. It would be a little more difficult to get by using only one or other of while
or do while
, as the difference between them is greater than the difference between prefix and postfix increment in my view.
And one could of course get by without using either prefix or postfix increment, or while
or do while
. But where do you draw the line between what's needless cruft and what's useful abstraction?
Upvotes: 1
Reputation: 4751
I think the only fair answer to which one to keep would be to do away with them both.
If, for example, you were to do away with postfix operators, then where code was once compactly expressed using n++
, you would now have to refer to (++n - 1)
, or you would have to rearrange other terms.
If you broke the increment or decrement out onto its own line before or after the expression which referred to n
, above, then it's not really relevant which you use, but in that case you could just as easily use neither, and replace that line with n = n + 1;
So perhaps the real issue, here, is expressions with side effects. If you like compact code then you'll see that both pre and post are necessary for different situations. Otherwise there doesn't seem to be much point in keeping either of them.
Example usage of each:
char array[10];
char * const end = array + sizeof(array) / sizeof(*array);
char *p = end;
int i = 0;
/* set array to { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } */
while (p > array)
*--p = i++;
p = array;
i = 0;
/* set array to { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } */
while (p < end)
*p++ = i++;
Upvotes: 1
Reputation: 4002
Prefix operator first increments value then its uses in the expression. Postfix operator,first uses the value in the expression and increments the value
The basic use of prefix/postfix operators are assembler replaces it with single increment/decrement instruction. If we use arithmetic operators instead of increment or decrement operators, assembler replaces it with two or three instructions. that's why we use increment/decrement operators.
Upvotes: 0