[C#] i = 0의 경우 (i + = i ++)가 0과 같은 이유는 무엇입니까?
다음 코드를 사용하십시오 (콘솔 응용 프로그램으로 사용 가능).
static void Main(string[] args)
{
int i = 0;
i += i++;
Console.WriteLine(i);
Console.ReadLine();
}
결과 i
는 0입니다. (내 동료 중 일부가했던 것처럼) 2를 기대했습니다. 아마도 컴파일러 i
는 0 이 되는 일종의 구조를 만듭니다 .
내가 2를 예상 한 이유는 내 생각에 오른쪽 문장이 먼저 평가되어 i가 1 씩 증가하기 때문입니다. i는 이미 1이므로 1에 1을 더하고 있습니다. 1 + 1 = 2입니다. 분명히 이것은 일어나지 않습니다.
컴파일러가 무엇을하는지 또는 런타임에 어떻게되는지 설명 할 수 있습니까? 결과가 왜 0입니까?
일부 면책 조항 : 나는이 코드를 사용하지 않아야하며 아마도 사용해서는 안된다는 것을 알고 있습니다. 나는 결코하지 않을 것입니다. 그럼에도 불구하고, 왜 그런 식으로 행동하고 정확히 무슨 일이 일어나는지 아는 것이 흥미 롭습니다.
답변
이:
int i = 0;
i += i++
당신이하는 것처럼 볼 수 있습니다 (다음은 지나치게 단순화 된 것입니다).
int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result
실제로 발생하는 일은 그보다 더 관련이 있습니다. MSDN, 7.5.9 Postfix 증가 및 감소 연산자를 살펴보십시오 .
x ++ 또는 x– 형식의 접미사 증가 또는 감소 작업의 런타임 처리는 다음 단계로 구성됩니다.
x가 변수로 분류 된 경우 :
- 변수를 생성하기 위해 x를 평가합니다.
- x 값이 저장됩니다.
- 선택된 연산자는 x의 저장된 값을 인수로 사용하여 호출됩니다.
- 연산자가 반환 한 값은 x의 평가에 의해 주어진 위치에 저장됩니다.
- 저장된 x 값은 작업 결과가됩니다.
때문에 유의 우선 순위 , 접미사가 ++
발생 하기 전에 +=
, 그러나 미사용 인 것을 결과 단부 (이전 값이 i
사용된다).
의보다 철저한 분해 i += i++
가 구성되어 부품을 모두 알고 하나를 필요로하지 않습니다 +=
및 ++
원자하지 않은 (즉, 둘 중 하나는 하나의 작업입니다) 그들이처럼 그들이 보이는 경우에도. 구현 방법에는 임시 변수, i
작업을 수행하기 전의 복사본 ( 각 작업마다 하나씩)이 포함됩니다. ( 와 각각에 사용되는 임시 변수에 이름 iAdd
과 이름을 사용합니다 ).iAssign
++
+=
따라서 발생하는 상황에 더 가까운 근사치는 다음과 같습니다.
int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=
i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;
답변
실행중인 코드의 분해 :
int i = 0;
xor edx, edx
mov dword ptr i, edx // set i = 0
i += i++;
mov eax, dword ptr i // set eax = i (=0)
mov dword ptr tempVar1, eax // set tempVar1 = eax (=0)
mov eax, dword ptr i // set eax = 0 ( again... why??? =\ )
mov dword ptr tempVar2, eax // set tempVar2 = eax (=0)
inc dword ptr i // set i = i+1 (=1)
mov eax, dword ptr tempVar1 // set eax = tempVar1 (=0)
add eax, dword ptr tempVar2 // set eax = eax+tempVar2 (=0)
mov dword ptr i, eax // set i = eax (=0)
동등한 코드
다음 코드와 동일한 코드로 컴파일됩니다.
int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;
두 번째 코드의 분해 (동일 함을 증명하기 위해)
int i, tempVar1, tempVar2;
i = 0;
xor edx, edx
mov dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
mov eax, dword ptr i
mov dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
mov eax, dword ptr i
mov dword ptr tempVar2, eax
++i;
inc dword ptr i
i = tempVar1 + tempVar2;
mov eax, dword ptr tempVar1
add eax, dword ptr tempVar2
mov dword ptr i, eax
분해 창 열기
대부분의 사람들은 Visual Studio 디스 어셈블리 창을 사용하여 최종 메모리 내 어셈블리 코드를 볼 수 있다는 것을 모릅니다 . 실행되고있는 머신 코드를 보여줍니다. CIL이 아닙니다.
디버깅하는 동안 이것을 사용하십시오 :
Debug (menu) -> Windows (submenu) -> Disassembly
postfix ++에서 무슨 일이 일어나고 있습니까?
postfix ++는 평가 후 피연산자의 값을 늘리고 싶다고 말합니다. 모두가 알고있는 것은 “평가 후” 의 의미입니다 .
그래서 않습니다 “평가 후” 수단 :
- 동일한 코드 행에서 피연산자의 다른 사용법은 영향을 받아야합니다.
a = i++ + i
두 번째 i는 증분의 영향을받습니다Func(i++, i)
두 번째 나는 영향을받습니다
- 같은 동일 라인에 대하여 단락 연산자의 다른 용도
||
및&&
:(false && i++ != i) || i == 0
세 번째 i는 평가되지 않기 때문에 i ++의 영향을받지 않습니다.
따라서 의미는 무엇 i += i++;
입니까?
와 동일 i = i + i++;
평가 순서는 다음과 같습니다.
- i + i 저장 (즉, 0 + 0)
- 증가 i (i가 1이 됨)
- 1 단계의 값을 i에 지정하십시오 (i는 0이됩니다).
증분이 삭제되지 않습니다.
의 의미는 무엇입니까 i = i++ + i;
?
이것은 이전 예제와 동일하지 않습니다. 세 번째 i
는 증분의 영향을받습니다.
평가 순서는 다음과 같습니다.
- i 저장 (즉, 0)
- 증가 i (i가 1이 됨)
- 단계 1 + i의 저장 값 (즉, 0 + 1)
- 3 단계의 값을 i에 할당하십시오 (i는 1이됩니다).
답변
int i = 0;
i += i++;
다음과 같이 평가됩니다.
Stack<int> stack = new Stack<int>();
int i;
// int i = 0;
stack.Push(0); // push 0
i = stack.Pop(); // pop 0 --> i == 0
// i += i++;
stack.Push(i); // push 0
stack.Push(i); // push 0
stack.Push(i); // push 0
stack.Push(1); // push 1
i = stack.Pop() + stack.Pop(); // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop(); // pop 0 and 0 --> i == 0
즉 i
, i++
표현식에 의해 한 번, +=
명령문에 의해 한 번 두 번 변경됩니다 .
그러나 +=
진술 의 피연산자 는
- 값
i
의 평가 전에i++
(의 좌측면+=
)과 - (의 오른쪽)
i
평가 전의 값 .i++
+=
답변
먼저 i++
0을 반환합니다. 그런 다음 i
1 씩 증가합니다. 마지막으로 i
초기 값에 i
0을 더한 값과 i++
0도 함께 설정됩니다. 0 + 0 = 0
답변
이것은 추상 구문 트리의 왼쪽에서 오른쪽으로 상향식 평가입니다. 개념적으로 식의 트리는 위에서 아래로 내려가지만 재귀가 맨 아래에서 트리로 다시 올라 오면서 평가가 전개됩니다.
// source code
i += i++;
// abstract syntax tree
+=
/ \
i ++ (post)
\
i
루트 노드를 고려하여 평가를 시작합니다 +=
. 이것이 표현의 주요 구성 요소입니다. +=
변수를 저장하는 위치를 결정하고 0 인 이전 값을 얻으려면 왼쪽 피연산자를 평가해야합니다. 다음으로 오른쪽을 평가해야합니다.
오른쪽은 증분 후 ++
연산자입니다. 여기에는 하나의 피연산자 i
가 있으며 값의 소스와 값을 저장할 위치로 평가됩니다. 연산자는를 i
찾아서 찾은 다음 0
결과적 1
으로 해당 위치에 저장합니다 . 이전 값 0
을 반환하는 의미에 따라 이전 값을 반환합니다.
이제 제어는 +=
작업자 에게 돌아갑니다 . 이제 작업을 완료하는 데 필요한 모든 정보가 있습니다. 결과를 저장할 위치 (의 저장 위치 i
)와 이전 값을 알고 있으며 이전 값에 추가 할 값, 즉을 알고 있습니다 0
. 따라서 i
0으로 끝납니다.
Java와 마찬가지로 C #은 평가 순서를 수정하여 C 언어의 매우 비현실적인 측면을 삭제했습니다. 왼쪽에서 오른쪽, 상향식 : 코더가 예상 할 수있는 가장 명확한 순서입니다.
답변
때문에 i++
첫 번째 반환 값은, 다음을 증가시킵니다. 그러나 i가 1로 설정되면 다시 0으로 설정합니다.
답변
증가 후 방법은 다음과 같습니다.
int ++(ref int i)
{
int c = i;
i = i + 1;
return c;
}
따라서 기본적으로을 호출 i++
하면 i
증분이지만 원래 값은 0으로 반환됩니다.