i = 0의 경우, (i += i++)가 0과 같은 이유는 무엇입니까?
다음 코드를 사용합니다(콘솔 응용 프로그램으로 사용 가능).
static void Main(string[] args)
{
int i = 0;
i += i++;
Console.WriteLine(i);
Console.ReadLine();
}
의 결과i
0입니다. (일부 동료들이 그랬던 것처럼) 2개를 예상했습니다.아마도 컴파일러는 다음과 같은 결과를 초래하는 일종의 구조를 만들 것입니다.i
영이 아닌
제가 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 수정 후 증분 및 감소 연산자를 살펴보면 실제로 발생하는 것은 그보다 더 중요합니다.
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 Disassembly 창을 사용하여 메모리 내 최종 어셈블리 코드를 볼 수 있는지 모르거나 기억하지 못합니다.실행 중인 기계 코드를 보여줍니다. CIL이 아닙니다.
디버깅하는 동안 사용:
Debug (menu) -> Windows (submenu) -> Disassembly
그렇다면 포스트픽스++에서는 어떤 일이 일어나고 있습니까?
포스트픽스++는 평가 후 피연산자의 값을 증가시키고 싶다고 말합니다...모두가 알고 있는...약간 혼란스러운 것은 "평가 후"의 의미입니다.
따라서 "평가 후"의 의미는 다음과 같습니다.
- 동일한 코드 라인에서 피연산자의 다른 용도가 영향을 받아야 합니다.
a = 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;
?
이는 이전 예제와 다릅니다. 회3제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
인 의초값으설니다됩정로기▁the로 되어 있습니다.i
에 0을 더한 값입니다.i++
반환됨, 이 역시 0입니다.0 + 0 = 0.
이것은 추상 구문 트리의 왼쪽에서 오른쪽으로 상향식 평가입니다.개념적으로 표현식의 트리는 위에서 아래로 이동하지만 재귀가 아래에서 트리 위로 다시 팝업되면서 평가가 진행됩니다.
// source code
i += i++;
// abstract syntax tree
+=
/ \
i ++ (post)
\
i
노드 평는루노고드것시으다작니됩로는려를 으로 시작합니다.+=
그것이 그 표현의 주요 구성 요소입니다.의 왼쪽 .+=
변수를 저장하는 위치를 결정하고 0인 이전 값을 얻기 위해 평가해야 합니다.다음으로, 오른쪽을 평가해야 합니다.
입니다.++
교환입니다.피연산자가 하나야i
이는 값의 소스 및 값을 저장할 장소로 평가됩니다.는 작자업가평다니합가.i
, 검색0
으로 그고결으저로장다니합적과리를 합니다.1
그장로소. 이값반환니다를 합니다.0
이전 값을 반환하는 의미에 따라.
이제 제어권은 다음 단계로 돌아갑니다.+=
완료할 됩니다.이제 작업을 완료하기 위한 모든 정보가 있습니다.를 저장하는 장소)를 알고 있습니다.i
값,값에 값, 즉 ) 및 이 값 전 값 추 가 할 가 치 가 있 습 니 에 다 즉 이 전 ▁) 있 니 습 다 가 가 치 추 할 ▁the ▁to 가 ▁to ▁value , ▁added ▁value ▁as , ▁value ▁namely ▁has0
.그렇게,i
으로 .으로 끝납니다.
Java와 마찬가지로 C#는 평가 순서를 수정하여 C 언어의 매우 미묘한 측면을 삭제했습니다.왼쪽에서 오른쪽으로, 상향식: 코더가 예상할 수 있는 가장 확실한 순서입니다.
ㅠㅠi++
먼저 값을 반환한 다음 증분합니다.그러나 i를 1로 설정한 후에는 다시 0으로 설정합니다.
사후 증분 방법은 다음과 같습니다.
int ++(ref int i)
{
int c = i;
i = i + 1;
return c;
}
그래서 기본적으로 당신이 전화할 때i++
,i
는 증분이지만 0인 경우 원래 값이 반환됩니다.
단순답변
int i = 0;
i += i++;
// Translates to:
i = i + 0; // because post increment returns the current value 0 of i
// Before the above operation is set, i will be incremented to 1
// Now i gets set after the increment,
// so the original returned value of i will be taken.
i = 0;
i++는 다음을 의미합니다: i의 값을 반환한 다음 증분합니다.
i += i + +는 다음을 의미합니다.i의 현재 값을 가져옵니다.i++의 결과를 추가합니다.
이제 i = 0을 시작 조건으로 추가하겠습니다.i += i++는 이제 다음과 같이 평가됩니다.
- i의 현재 값은 얼마입니까?0입니다.i++의 결과를 추가할 수 있도록 저장합니다.
- i++ 평가(i의 현재 값이므로 0으로 평가)
- 저장된 값을 로드하고 2단계의 결과를 추가합니다. (0에서 0 추가)
참고: 2단계 끝에서 i의 값은 실제로 1입니다.그러나 3단계에서는 i 값이 증가하기 전에 i 값을 로드하여 삭제합니다.
i++와 반대로 +++i는 증분 값을 반환합니다.
따라서 i+= ++i는 1을 제공합니다.
연산자, 수정후연산자분증,++
변수에 식의 값을 제공한 다음 할당한 증분을 수행하여 0(0) 값을 다시 반환하고 증분 값(1)을 덮어쓰므로 0이 됩니다.증분 연산자에 대한 자세한 내용은 ++ 연산자(MSDN)에서 확인할 수 있습니다.
i += i++;
0과 같을 것입니다, 왜냐하면 그것은 하기 때문입니다.++
사후에
i += ++i;
하기 전에 할 것입니다
++ 포스트픽스는 다음을 평가합니다.i
하기 전에, 증하기전에그, 고리가.+=
는 평만합니다가만 합니다.i
한번만.
+ = 0 + 0 = 0, 0 + 0 ▁0 0,i
은 " " " " " 입니다.++
사용됩니다.갖기 위해i
증분, 먼저 증분접, 형사용식사두▁((용사▁the▁incre▁prefix먼▁use▁form형,)을 사용합니다.++i
).
(또한 참고: 0 + (0 + 1) = 1이므로 1만 표시해야 합니다.)
참고 자료: http://msdn.microsoft.com/en-us/library/sa7629ew.aspx (+=)
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx (++)
C#가 무엇을 하고 있는지, 그리고 혼란의 "이유"
저도 그 값이 1이 될 것으로 예상했습니다만... 그 문제에 대한 어떤 탐구는 몇 가지 요점을 분명히 했습니다.
다음 방법을 고려합니다.
static int SetSum(ref int a, int b) { return a += b; }
static int Inc(ref int a) { return a++; }
는 그것을 했습니다.i += i++
SetSum(ref i, Inc(ref i))
이 문 뒤의 i 값은 1:
int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1
하지만 또 다른 결론에 도달했어요 i += i++
와 실제로 동일합니다.i = i + i++
그래서 저는 다음과 같은 기능을 사용하여 또 다른 유사한 예제를 만들었습니다.
static int Sum(int a, int b) { return a + b; }
static int Set(ref int a, int b) { return a = b; }
을 것이을부후에라고 부른 Set(ref i, Sum(i, Inc(ref i)))
i의 값은 0입니다.
int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0
이것은 C#이 무엇을 하고 있는지 설명할 뿐만 아니라...하지만 왜 많은 사람들이 그것을 혼동했는지도...나를 포함해서요.
내가 항상 기억하는 좋은 기억법은 다음과 같습니다.
한다면++
식 뒤에 있는 stands는 이전 값을 반환합니다.그래서 다음 코드는
int a = 1;
int b = a++;
1입니다, 왜냐하면a
그것이 증가하기 전에 1이었습니다.++
뒤에 서 있는. a
사람들은 이것을 포스트픽스 표기법이라고 부릅니다.또한 접두사 표기법이 있는데, 여기서 상황은 정확히 반대입니다: 만약++
앞에 서고, 식은 작업 후의 값을 반환합니다.
int a = 1;
int b = ++a;
b
여기에 두 개가 있습니다.
그래서 당신의 코드에 대해 이것은
int i = 0;
i += (i++);
i++
). 따라서 0을 반환합니다.0 + 0 = 0
.
i += (++i); // Here 'i' would become two
Scott Meyers는 "효과적인 C++ 프로그래밍"에서 이 두 표기법의 차이를 설명합니다.내부적으로.i++
는 값(postfix)을 합니다.i
접두사 (was , ▁(▁the)를 호출합니다.++i
하고 이전 값( )을 합니다.i
이것이 당신이 항상 사용해야 하는 이유입니다.++i
for
루프(모든 현대 컴파일러가 번역하고 있다고 생각하지만)i++
++i
for
루프).
당신의 질문에 대한 유일한 정답은 다음과 같습니다. 왜냐하면 그것은 정의되지 않았기 때문입니다.
i+=i++;
▁in로가 나다0
정의되지 않았습니다.
언어 평가 메커니즘의 버그입니다.심지어 더 나쁜 것! 디자인의 버그.
증거를 원하십니까?물론 당신은 원합니다!
int t=0; int i=0; t+=i++; //t=0; i=1
자, 이건...직관적인 결과입니다! 왜냐하면 우리가 처음 평가했기 때문입니다.t
값을 지정하고 평가 및 할당 후에만 사후 작업이 발생했습니다. 합리적이지 않습니까?
같은 입니까?i=i++
그리고.i=i
수 .i
?
하는 동안에t=i++
그리고.t=i
다 니 를 습 과 른 ▁for ▁have ▁ ▁i
.
사후 작업은 명세서 평가 후에 이루어져야 합니다.
따라서:
int i=0;
i+=i++;
다음과 같이 적었더라도 동일해야 합니다.
int i=0;
i = i + i ++;
따라서 다음과 같습니다.
int i=0;
i= i + i;
i ++;
따라서 다음과 같습니다.
int i=0;
i = i + i;
i = i + 1;
이 아닌 1
우리가 합리적인 생각을 한다면 컴파일러의 버그나 언어 디자인의 버그를 나타냅니다. 하지만 MSDN과 많은 다른 출처들은 우리에게 "이봐요, 이것은 정의되지 않았어요!"라고 말합니다.
자, 계속하기 전에, 제가 제시한 이 예시들조차도 그 누구도 지지하거나 인정하지 않습니다.그러나 이것은 직관적이고 합리적인 방법에 따라 결과가 되어야 하는 것입니다.
코더는 어셈블리가 어떻게 작성되거나 번역되는지 알지 못합니다!
만약 그것이 언어 정의를 존중하지 않는 방식으로 쓰여진다면, 그것은 버그입니다!
마지막으로 위키백과의 증분 및 감소 연산자에서 이를 복사했습니다.
증분/감소 연산자는 피연산자를 수정하므로 동일한 식 내에서 이러한 피연산자를 두 번 이상 사용하면 정의되지 않은 결과가 생성될 수 있습니다.예를 들어, x - ++x와 같은 식에서는 감산 및 증분 연산자를 어떤 순서로 수행해야 하는지 명확하지 않습니다.컴파일러에 의해 최적화가 적용되면 이러한 상황은 더욱 악화되어 작업 실행 순서가 프로그래머가 의도한 것과 다를 수 있습니다.
그러므로.
는 안 (되지 않았기 정답은 이것을 사용해서는 안 된다는 것입니다! (정의되지 않았기 때문에!)
네.. - C#컴플라이어가 어떻게든 정상화하려고 해도 예측할 수 없는 결과가 나옵니다.
저는 여러분 모두가 문서화된 행동을 언어의 정상적이거나 잘 정의된 행동으로 설명하는 C# 문서를 찾지 못했습니다.제가 발견한 것은 정반대입니다!
[포스트픽스 증분 및 감소 연산자에 대한 MSDN 문서에서 복사: ++ 및 --]
사후 수정 연산자가 함수 인수에 적용되는 경우 인수 값이 함수에 전달되기 전에 증가하거나 감소하는 것이 보장되지 않습니다.자세한 내용은 C++ 표준의 섹션 1.9.17을 참조하십시오.
그 단어들이 보장되지 않는다는 것을 알아두세요...
변수 뒤의 ++ 연산자를 사용하면 사후 수정 증분이 됩니다.증가는 문의 다른 모든 항목, 추가 및 할당 다음에 발생합니다.대신 변수 앞에 ++를 놓으면 i 값이 평가되기 전에 발생하고 예상되는 답을 얻을 수 있습니다.
계산 단계는 다음과 같습니다.
int i=0
됨 //0으로 설정됨i+=i++
//식등i=i+i++
한 후 //컴파일러단순후한화방정을로식▁/▁simpl후▁by한▁equation▁//화/.i=0+i++
값 //i 값체대i=0+0
는 아래 입니다. /i++는 0입니다.i=0
i //최종 결과 i=0
에는 여서기, 처는의값다니입의 입니다.i
0. WKT.i++
불과합니다. 다이아: 먼사합니다용저니라를 합니다.i
을 매긴 시킵니다.i
값을 1로 매기다그래서 그것은 사용합니다.i
값, 0, 계를 하는 동안i++
그런 다음 1씩 증가시킵니다.따라서 값은 0이 됩니다.
매우 조심하세요: C FAQ를 읽어보세요: 당신이 하려는 것 (과제와 혼합)++
동일한 변수의)는 지정되지 않았을 뿐만 아니라 정의되지 않았습니다(컴파일러가!를 평가할 때 "합리적인" 결과를 제공할 뿐만 아니라 무엇이든 할 수 있음을 의미합니다).
섹션 3을 읽어주세요.전체 섹션은 읽을 가치가 충분히 있습니다!특히 3.9는 불특정의 의미를 설명합니다.섹션 3.3에서는 "i++" 등으로 수행할 수 있는 작업과 수행할 수 없는 작업을 간략하게 요약합니다.
컴파일러 내부에 따라 0, 2, 1 또는 다른 모든 것을 얻을 수 있습니다!그리고 그것은 정의되지 않았기 때문에, 그들은 그렇게 하는 것이 좋습니다.
두 가지 옵션이 있습니다.
첫 번째 옵션: 컴파일러가 다음과 같이 문장을 읽는다면,
i++;
i+=i;
결과는 2입니다.
위해서
else if
i+=0;
i++;
결과는 1입니다.
위의 답변에는 훌륭한 추론이 많이 있습니다. 저는 작은 테스트를 했고 여러분과 공유하고 싶습니다.
int i = 0;
i+ = i++;
여기 결과 i는 0 결과를 보여주고 있습니다.이제 아래의 경우를 고려해 보겠습니다.
사례 1:
i = i++ + i; //Answer 1
이전에 나는 위의 코드가 이것과 비슷하다고 생각했기 때문에 처음에 답은 1이고, 이것에 대한 i의 진짜 답은 1입니다.
사례 2:
i = i + i++; //Answer 0 this resembles the question code.
여기서 증분 연산자는 i++가 추가 전에 실행할 기회가 있는 이전의 경우와 달리 실행 경로에 오지 않습니다.
이것이 조금이나마 도움이 되었으면 좋겠습니다.감사해요.
C 프로그래밍 101 유형의 관점에서 이것에 답하기를 바랍니다.
제가 보기에는 다음과 같은 순서로 일어나고 있는 것 같습니다.
i
되어 0이 됩니다.i = 0 + 0
연산을 사용하여i++
하면 "complete"가 됩니다.i
아직 일어나지 않았습니다.i++
- 는 다음과 .
i = 0
위에서 발생하여 #2(후퇴자)가 했을 것을 효과적으로 덮어씁니다.
#2는 실제로 일어나지 않을 수도 있습니다. 왜냐하면 컴파일러는 아무런 목적도 달성하지 못할 것이기 때문입니다. 하지만 이것은 컴파일러에 의존적일 수 있습니다.어느 쪽이든, 다른 지식이 풍부한 답변들은 결과가 정확하고 C# 표준을 준수한다는 것을 보여주었지만, 여기서 C/C++에 대해 어떤 일이 일어나는지는 정의되지 않았습니다.
어떻게, 왜 그런지는 제가 전문적으로 파악할 수 없는 부분인데 앞서 평가한 오른쪽 측면 과제가 포스트 인크리먼트 이후에 일어난다는 점이 아마 여기서 헷갈리는 부분일 겁니다.
또한, 당신은 당신이 하지 않는 한 결과가 2가 될 것이라고 기대하지 않을 것입니다.++i
에 i++
믿어요.
간단히 말해서,
i++는 "+=" 연산자가 완료된 후 "i"에 1을 추가합니다.
원하는 것은 ++i이므로 "+=" 연산자가 실행되기 전에 "i"에 1을 추가합니다.
i=0
i+=i
i=i+1
i=0;
그러면 1이 다음에 추가됩니다.i
.
i+=i++
에 래서을 1추가하전에기그▁so.i
,i
.0의값 사습니다했의 .에만 앞개 1를더해야에.i
0값 0을 를 가져옵니다.
i+=++i
i=2
은 그대은답입니다.i
▁▁be 될 것입니다.1
.
방법을 살펴보겠습니다.
처음에는i=0;
.
그러면 계산하면서.i +=i++;
가치에 따라 우리는 다음과 같은 것을 갖게 될 것입니다.0 +=0++;
우선순위에 라따서운의우선순위에따라자영▁so따라에▁operator▁to▁preced위▁according0+=0
먼저 수행하고 결과는 다음과 같습니다.0
.
가 그면증연다같음적이용다됩0++
,~하듯이0+1
그고 그가 치리의 값.i
▁▁be 될 것입니다.1
.
언급URL : https://stackoverflow.com/questions/13516689/for-i-0-why-is-i-i-equal-to-0
'programing' 카테고리의 다른 글
Windows 및 Linux 디렉터리 이름에서 금지된 문자는 무엇입니까? (0) | 2023.05.28 |
---|---|
f-flash 대 str.format » (0) | 2023.05.28 |
IN 값 목록을 기준으로 주문 (0) | 2023.05.28 |
날짜가 발생한 횟수를 세어 그래프를 만듭니다. (0) | 2023.05.28 |
셸에서 for-loop에 선행 0을 추가하는 방법은 무엇입니까? (0) | 2023.05.28 |