I've seen them both being used in numerous pieces of C# code, and I'd like to know when to use i++
and when to use ++i
?
(i
being a number variable like int
, float
, double
, etc).
Oddly it looks like the other two answers don't spell it out, and it's definitely worth saying:
i++
means 'tell me the value of i
, then increment'
++i
means 'increment i
, then tell me the value'
They are Pre-increment, post-increment operators. In both cases the variable is incremented, but if you were to take the value of both expressions in exactly the same cases, the result will differ.
int[] arr = {0}; int value = arr[arr[0]++];
) is the simplest one I can think of where this order causes an issue. I can't offer a better one. –
Fancy i++
means 'tell me the value of i, then increment'. In this example, arr[0]++
says tell me the value of arr[0]
, then increment. I don't say when it will happen, or allude that it happens before or after anything else is evaluated. Also, Eric's first linked blog post explains the fine details of when evaluations and side-effects occur: but simply put, I don't say anything different! –
Cutoff i
, then increment' - which is correct. My addendum of 'I don't say when' is with regards to anything else the user might care to craft into that statement / line. So, once again, "i++
" means "tell me the value of i, then increment". The extra part was to say I don't cover things like "(++i)[j++] = i++ + ++j
". I'm saying the difference between i++
and ++i
. –
Cutoff i
is returned. "increment, then tell me the previous value of i
" would be correct. You don't need to add the extra details in order to make a correct statement. –
Violation a == int.MaxValue
in the catch block. –
Danyelldanyelle a
is "told the value of i
" before i
is incremented creates the wrong impression about the effect on a
: int i = int.MaxValue; int a = 0; try { checked { a = i++; } } catch { Console.WriteLine(a); }
The output is 0
because a
isn't told anything until after i
is incremented. Incrementing i
throws an exception and a
remains unchanged. –
Danyelldanyelle The typical answer to this question, unfortunately posted here already, is that one does the increment "before" remaining operations and the other does the increment "after" remaining operations. Though that intuitively gets the idea across, that statement is on the face of it completely wrong. The sequence of events in time is extremely well-defined in C#, and it is emphatically not the case that the prefix (++var) and postfix (var++) versions of ++ do things in a different order with respect to other operations.
It is unsurprising that you'll see a lot of wrong answers to this question. A great many "teach yourself C#" books also get it wrong. Also, the way C# does it is different than how C does it. Many people reason as though C# and C are the same language; they are not. The design of the increment and decrement operators in C# in my opinion avoids the design flaws of these operators in C.
There are two questions that must be answered to determine what exactly the operation of prefix and postfix ++ are in C#. The first question is what is the result? and the second question is when does the side effect of the increment take place?
It is not obvious what the answer to either question is, but it is actually quite simple once you see it. Let me spell out for you precisely what x++ and ++x do for a variable x.
For the prefix form (++x):
- x is evaluated to produce the variable
- The value of the variable is copied to a temporary location
- The temporary value is incremented to produce a new value (not overwriting the temporary!)
- The new value is stored in the variable
- The result of the operation is the new value (i.e. the incremented value of the temporary)
For the postfix form (x++):
- x is evaluated to produce the variable
- The value of the variable is copied to a temporary location
- The temporary value is incremented to produce a new value (not overwriting the temporary!)
- The new value is stored in the variable
- The result of the operation is the value of the temporary
Some things to notice:
First, the order of events in time is exactly the same in both cases. Again, it is absolutely not the case that the order of events in time changes between prefix and postfix. It is entirely false to say that the evaluation happens before other evaluations or after other evaluations. The evaluations happen in exactly the same order in both cases as you can see by steps 1 through 4 being identical. The only difference is the last step - whether the result is the value of the temporary, or the new, incremented value.
You can easily demonstrate this with a simple C# console app:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine($"Current:{Application.currentValue} Passed-in:{passedInValue}");
}
}
Here are the results...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
In the first test, you can see that both currentValue
and what was passed into the TestMethod()
extension show the same value, as expected.
However, in the second case, people will try to tell you that the increment of currentValue
happens after the call to TestMethod()
, but as you can see from the results, it happens before the call as indicated by the 'Current:2' result.
In this case, first the value of currentValue
is stored in a temporary. Next, an incremented version of that value is stored back in currentValue
but without touching the temporary which still stores the original value. Finally that temporary is passed to TestMethod()
. If the increment happened after the call to TestMethod()
then it would write out the same, non-incremented value twice, but it does not.
It's important to note that the value returned from both the
currentValue++
and++currentValue
operations are based on the temporary and not the actual value stored in the variable at the time either operation exits.Recall in the order of operations above, the first two steps copy the then-current value of the variable into the temporary. That is what's used to calculate the return value; in the case of the prefix version, it's that temporary value incremented while in the case of the suffix version, it's that value directly/non-incremented. The variable itself is not read again after the initial storage into the temporary.
Put more simply, the postfix version returns the value that was read from the variable (i.e. the value of the temporary) while the prefix version returns the value that was written back to the variable (i.e. the incremented value of the temporary). Neither return the variable's value.
This is important to understand because the variable itself could be volatile and have changed on another thread which means the return value of those operations could differ from the current value stored in the variable.
It is surprisingly common for people to get very confused about precedence, associativity, and the order in which side effects are executed, I suspect mostly because it is so confusing in C. C# has been carefully designed to be less confusing in all these regards. For some additional analysis of these issues, including me further demonstrating the falsity of the idea that prefix and postfix operations "move stuff around in time" see:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
which led to this SO question:
int[] arr={0}; int value = arr[arr[0]++]; Value = 1?
You might also be interested in my previous articles on the subject:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
and
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
and an interesting case where C makes it hard to reason about correctness:
https://learn.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Also, we run into similar subtle issues when considering other operations that have side effects, such as chained simple assignments:
https://learn.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
And here's an interesting post on why the increment operators result in values in C# rather than in variables:
i++
or ++i
are used in code, the things going on in the background are just that; in the background. I write C# to climb to abstraction levels above what's going on on this level, so if this really matters for your C# code, you might already be in the wrong language. –
Ube i++;
) is in for (int i = 0; i < x; i++)
... And I'm very very happy of this! (and I don't ever ever use the prefix operator). If I have to write something that will require a senior programmer 2 minutes to decipher... Well... It's better to write one more line of code or introduce a temporary variable :-) I think that your "article" (I won't call it "answer") vindicates my choice :-) –
Predella x += 1
equivalent to ++x
(in terms of the compiler)? –
Adamina x
is a user-defined type, for instance, then for x += 1
the compiler generates a call to operator+
, but for x++
the compiler generates a call to operator++
. If you mean for x
a variable of type int
, does the language require that x+=1
and ++x
have the same semantics, yes, it does. If that's not what you meant then please clarify the question or consider asking your question as a question rather than a comment. –
Drida Oddly it looks like the other two answers don't spell it out, and it's definitely worth saying:
i++
means 'tell me the value of i
, then increment'
++i
means 'increment i
, then tell me the value'
They are Pre-increment, post-increment operators. In both cases the variable is incremented, but if you were to take the value of both expressions in exactly the same cases, the result will differ.
int[] arr = {0}; int value = arr[arr[0]++];
) is the simplest one I can think of where this order causes an issue. I can't offer a better one. –
Fancy i++
means 'tell me the value of i, then increment'. In this example, arr[0]++
says tell me the value of arr[0]
, then increment. I don't say when it will happen, or allude that it happens before or after anything else is evaluated. Also, Eric's first linked blog post explains the fine details of when evaluations and side-effects occur: but simply put, I don't say anything different! –
Cutoff i
, then increment' - which is correct. My addendum of 'I don't say when' is with regards to anything else the user might care to craft into that statement / line. So, once again, "i++
" means "tell me the value of i, then increment". The extra part was to say I don't cover things like "(++i)[j++] = i++ + ++j
". I'm saying the difference between i++
and ++i
. –
Cutoff i
is returned. "increment, then tell me the previous value of i
" would be correct. You don't need to add the extra details in order to make a correct statement. –
Violation a == int.MaxValue
in the catch block. –
Danyelldanyelle a
is "told the value of i
" before i
is incremented creates the wrong impression about the effect on a
: int i = int.MaxValue; int a = 0; try { checked { a = i++; } } catch { Console.WriteLine(a); }
The output is 0
because a
isn't told anything until after i
is incremented. Incrementing i
throws an exception and a
remains unchanged. –
Danyelldanyelle If you have:
int i = 10;
int x = ++i;
then x
will be 11
.
But if you have:
int i = 10;
int x = i++;
then x
will be 10
.
Note as Eric points out, the increment occurs at the same time in both cases, but it's what value is given as the result that differs (thanks Eric!).
Generally, I like to use ++i
unless there's a good reason not to. For example, when writing a loop, I like to use:
for (int i = 0; i < 10; ++i) {
}
Or, if I just need to increment a variable, I like to use:
++x;
Normally, one way or the other doesn't have much significance and comes down to coding style, but if you are using the operators inside other assignments (like in my original examples), it's important to be aware of potential side effects.
i
for the variable name rather than var
as it is a C# keyword. –
Intercede ++x;
and ++i
goes against any convention I've seen, but then again, I haven't seen that many... –
Sadiron for
loop. –
Sadiron int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.
Does this answer your question ?
The way the operator works is that it gets incremented at the same time, but if it is before a variable, the expression will evaluate with the incremented/decremented variable:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
If it is after the variable the current statement will get executed with the original variable, as if it had not yet been incremented/decremented:
int x = 0; //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0
I agree with dcp in using pre-increment/decrement (++x) unless necessary. Really the only time I use the post-increment/decrement is in while loops or loops of that sort. These loops are the same:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
or
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
You can also do this while indexing arrays and such:
int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678; //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);
Etc, etc...
Just for the record, in C++, if you can use either (i.e.) you don't care about the ordering of operations (you just want to increment or decrement and use it later) the prefix operator is more efficient since it doesn't have to create a temporary copy of the object. Unfortunately, most people use posfix (var++) instead of prefix (++var), just because that is what we learned initially. (I was asked about this in an interview). Not sure if this is true in C#, but I assume it would be.
I think I'll try answering the question using code. Imagine the following methods for, say, int
:
// The following are equivalent:
// ++i;
// PlusPlusInt(ref i);
//
// The argument "value" is passed as a reference,
// meaning we're not incrementing a copy.
static int PlusPlusInt(ref int value)
{
// Increment the value.
value = value + 1;
// Return the incremented value.
return value;
}
// The following are equivalent:
// i++;
// IntPlusPlus(ref i);
//
// The argument "value" is passed as a reference,
// meaning we're not incrementing a copy.
static int IntPlusPlus(ref int value)
{
// Keep the original value around before incrementing it.
int temp = value;
// Increment the value.
value = value + 1;
// Return what the value WAS.
return temp;
}
Assuming you know how ref
works, this should clear this up really nicely. Explaining it in english is a lot more clunky in my opinion.
© 2022 - 2024 — McMap. All rights reserved.