i ++와 ++ i의 차이점은 무엇입니까?
나는 모두 C # 코드의 많은 부분에서 사용되는 그들을 본 적이, 내가 사용하는 경우 알고 싶습니다
i++
또는
++i
(
i
같은 숫자 변수 인
int
,
float
,
double
, 등). 이것을 아는 사람이 있습니까?
이상하게도 다른 두 가지 대답이 철자를 쓰지 않는 것처럼 보이며 분명히 말할 가치가 있습니다.
i++
'의 값을 말한
i
다음 증가 시키십시오'를 의미합니다.
++i
``증가
i
, 그다음 가치를 말하십시오 ''를 의미
사전 증가, 사후 증가 연산자입니다.
두 경우 모두 변수가 증가
하지만 정확히 동일한 경우 두 표현식의 값을 가져 오면 결과가 달라집니다.
불행히도 여기에 이미 게시 된이 질문에 대한 일반적인 대답은 하나는 남은 작업 전에 "증가"를 수행하고 다른 하나는 남은 작업 후에 "증가"를 수행한다는 것입니다.
그것이 직관적으로 아이디어를 얻었지만, 그 진술은 완전히 잘못되었습니다
.
시간에 이벤트의 순서는
매우 C #으로 잘 정의이며, 단호하다
하지
++의 접두사 (++ VAR)와 후위 (VAR ++) 버전이 다른 작업에 대한 다른 순서로 일을하는 경우.이 질문에 대해 많은 잘못된 답변을 보게 될 것은 놀라운 일이 아닙니다. 많은 "C #을 가르쳐라"책도 잘못 이해합니다. 또한 C #의 방식은 C의 방식과 다릅니다. 많은 사람들이 C #과 C가 같은 언어 인 것처럼 추론합니다. 그들은 아닙니다. 제 생각에 C #의 증가 및 감소 연산자의 디자인은 C에서 이러한 연산자의 디자인 결함을 피합니다.C #에서 prefix 및 postfix ++의 작동이 정확히 무엇인지 확인하려면 두 가지 질문에 대답해야합니다. 첫 번째 질문은
결과
가 무엇입니까? 두 번째 질문은
언제 증분의 부작용이 발생합니까?
두 질문에 대한 답이 무엇인지는 분명하지 않지만 일단 본 후에는 실제로 매우 간단합니다. 변수 x에 대해 x ++와 ++ x가하는 일을 정확하게 설명하겠습니다.접두사 형식 (++ x)의 경우 :
- x는 변수를 생성하기 위해 평가됩니다
- 변수 값이 임시 위치에 복사됩니다
- 임시 값이 증가하여 새 값을 생성합니다 (임시 값을 덮어 쓰지 않음).
- 새로운 값은 변수에 저장됩니다
- 연산 결과는 새로운 값 (즉, 임시 값의 증가 된 값)입니다.
접미사 형식 (x ++)의 경우 :
- x는 변수를 생성하기 위해 평가됩니다
- 변수 값이 임시 위치에 복사됩니다
- 임시 값이 증가하여 새 값을 생성합니다 (임시 값을 덮어 쓰지 않음).
- 새로운 값은 변수에 저장됩니다
- 작업 결과 는 임시 값입니다.
알아 두어야 할 사항 :첫째,
시간의 이벤트 순서는 두 경우 모두 동일합니다
. 다시 말하지만, 시간의 이벤트 순서가 접두사와 접두사 사이 에서 변경 되는 경우 는 절대
아닙니다
. 평가가 다른 평가 전에 또는 다른 평가 후에 발생한다고 말하는 것은 전적으로 거짓입니다. 1 단계에서 4 단계까지 동일하다는 것을 알 수 있듯이 두 경우 모두 동일한 순서 로 평가 가 수행됩니다. 유일한 차이점은입니다 마지막 단계 - 결과가 임시, 또는 새, 증가 값의 값이 있는지 여부.간단한 C # 콘솔 앱으로이를 쉽게 보여줄 수 있습니다.
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:{0} Passed-in:{1}",
Application.currentValue,
passedInValue);
}
}
결과는 다음과 같습니다.
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 in to 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:
http://blogs.msdn.com/b/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx
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:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/23/precedence-vs-associativity-vs-order.aspx
and
http://blogs.msdn.com/b/ericlippert/archive/2007/08/14/c-and-the-pit-of-despair.aspx
and an interesting case where C makes it hard to reason about correctness:
http://blogs.msdn.com/b/ericlippert/archive/2005/04/28/bad-recursion-revisited.aspx
Also, we run into similar subtle issues when considering other operations that have side effects, such as chained simple assignments:
And here's an interesting post on why the increment operators result in values in C# rather than in variables:
Why can't I do ++i++ in C-like languages?
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.
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.
참고URL : https://stackoverflow.com/questions/3346450/what-is-the-difference-between-i-and-i
'programing' 카테고리의 다른 글
CoffeeScript에서 객체의 키와 값을 반복하는 방법은 무엇입니까? (0) | 2020.05.14 |
---|---|
Aspect 지향 프로그래밍 vs. 객체 지향 프로그래밍 (0) | 2020.05.14 |
Android에서 URI 빌더를 사용하거나 변수가있는 URL을 작성하십시오. (0) | 2020.05.13 |
vim-줄을 세지 않고 큰 텍스트 블록을 삭제하는 방법? (0) | 2020.05.13 |
HTML 페이지에서 이미지 드래그 비활성화 (0) | 2020.05.13 |