i = 0의 경우 (i + = i ++)가 0과 같은 이유는 무엇입니까?


253

다음 코드를 사용하십시오 (콘솔 응용 프로그램으로 사용 가능).

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입니까?

일부 면책 조항 : 나는이 코드를 사용하지 않아야하며 아마도 사용해서는 안된다는 것을 알고 있습니다. 나는 결코하지 않을 것입니다. 그럼에도 불구하고, 왜 그런 식으로 행동하고 정확히 무슨 일이 일어나는지 아는 것이 흥미 롭습니다.


57
예상 결과가 1이 아니어야합니까? i (0) + = i ++ (1) 따라서 0 + = 1 = 1
aleation

11
그것은 예상대로 작동합니다
스티브는 D

177
이 질문의 몇 가지 변형이 요청됩니까?
mowwwalker

20
Preincrementation는 acction를 수행하기 전에 값을 증가합니다 내가 + = 내가 ++ 당신에게 줄 것 1
Pierluc SS

21
왜 모든 사람이 사전 및 사후 증가에 초점을 맞추고 있습니까? 은 "이상한"일이 있다는 것입니다 i왼쪽에 +=오른쪽 전에 "캐시"되는이 평가된다. 예를 들어 i객체 인 경우 복사 작업이 필요한 것처럼 이는 직관적이지 않습니다. (나를 오해하지 마십시오. 나는 그것이 0정확하고 표준에 맞는 답변 이라는 것을 전적으로 동의합니다 .)
JohnB

답변:


425

이:

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;

3
@Oded ++작업은 명령문 평가 가 완료 되기 전에 수행 됩니다. 따라서 +=값을 덮어 씁니다. 이것이 일어난 일입니까?
Anirudh Ramanathan

6
@Oded 실제로는 : int i = 0; i = i + 1; (postfix) i = 0; (assignment). 해당 문장의 다른 곳에서 i를 사용한 경우 당시에는 1로 평가됩니다.
drch

@Cthulhu-본질적으로. 대답 에 의해 DTB는 세부로 들어갑니다.
Oded

6
나는 이것을 사지 않는다. @yoriy의 답변이 훨씬 정확합니다. 하나, 당신의 대답에서, 당신은 마지막 줄이 될 i+1것이지만 반면에 있어야 한다고 말합니다 i=i+1. 그렇지 i++않습니까?
recluze

3
답의 첫 부분은 중복입니다. 마지막 코드 샘플은 IMHO를 수행했을 수 있습니다. 그래도 +1입니다.
corazza

194

실행중인 코드의 분해 :

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++;

평가 순서는 다음과 같습니다.

  1. i + i 저장 (즉, 0 + 0)
  2. 증가 i (i가 1이 됨)
  3. 1 단계의 값을 i에 지정하십시오 (i는 0이됩니다).

증분이 삭제되지 않습니다.

의 의미는 무엇입니까 i = i++ + i;?

이것은 이전 예제와 동일하지 않습니다. 세 번째 i는 증분의 영향을받습니다.

평가 순서는 다음과 같습니다.

  1. i 저장 (즉, 0)
  2. 증가 i (i가 1이 됨)
  3. 단계 1 + i의 저장 값 (즉, 0 + 1)
  4. 3 단계의 값을 i에 할당하십시오 (i는 1이됩니다).

22
+ 1 ++-하드 코어 해부 척 노리스는 자랑스러워 할 것입니다.) OP는 모노 포트가 아니라 인텔에 있다고 가정합니다.
StuartLC

19
C #에는 식에 대해 잘 정의 된 평가 순서가 있으며 개체 코드는 해당 순서를 구현합니다. 기계 코드 출력은 평가 순서의 이유나 설명이 아닙니다.
Kaz

8
기계어 코드를 사용하면 평가 순서가 IMO를 구현하는 방법을 쉽게 이해할 수 있습니다.
케빈

5
@StuartLC 나는 당신이 무엇을했는지 봅니다. 버려 졌다는 것에 대한 수치심.
Steffan Donal

2
a++ + aa + a++이것은 더 이상 순수한 수학이 아니기 때문에 동일 하지 않습니다. 대수학의 상용 성 법칙은 변수가 표현식을 통해 중간에 값을 변경할 가능성을 고려하지 않습니다. 프로그래밍이 함수형 프로그래밍 인 경우 수학은 프로그래밍에 깔끔하게 매핑됩니다. 그리고 심지어 표현상의 한계 때문에 말도 안됩니다. 예를 들어 부동 소수점 숫자는 때때로 실수처럼 행동하고 때로는 그렇지 않습니다. 부작용이 없어도 수학의 실수에 적용되는 commutativity 및 associativity 법칙은 부동 소수점 숫자보다 우선합니다.
Kaz

61
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+++=

아 이것은 환상적인 설명입니다. 역 광택 표기법을 사용하여 스택 기반 계산기에서 작업 할 때를 상기시킵니다.
Nathan

36

먼저 i++0을 반환합니다. 그런 다음 i1 씩 증가합니다. 마지막으로 i초기 값에 i0을 더한 값과 i++0도 함께 설정됩니다. 0 + 0 = 0


2
그러나 i += i++;는 아닙니다 i = i++;. 따라서 i++(0) 의 값 이에 추가되고 i" 반환 i된 값 i++으로 설정 되지 않습니다 ". 값을 추가 할 때 이제 질문은, i++반환을 i, 것 i증가 된 값 또는하지-증가 값은? 내 친구 인 대답은 사양에 기록되어 있습니다.
Daniel Fischer

사실, 나는 그것을 고칠 것이다. 어쨌든 이후 i = 0처음 i += something과 동일 i = 0 + something하다 i = something.
Jong

32

이것은 추상 구문 트리의 왼쪽에서 오른쪽으로 상향식 평가입니다. 개념적으로 식의 트리는 위에서 아래로 내려가지만 재귀가 맨 아래에서 트리로 다시 올라 오면서 평가가 전개됩니다.

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

루트 노드를 고려하여 평가를 시작합니다 +=. 이것이 표현의 주요 구성 요소입니다. +=변수를 저장하는 위치를 결정하고 0 인 이전 값을 얻으려면 왼쪽 피연산자를 평가해야합니다. 다음으로 오른쪽을 평가해야합니다.

오른쪽은 증분 후 ++연산자입니다. 여기에는 하나의 피연산자 i가 있으며 값의 소스와 값을 저장할 위치로 평가됩니다. 연산자는를 i찾아서 찾은 다음 0결과적 1으로 해당 위치에 저장합니다 . 이전 값 0을 반환하는 의미에 따라 이전 값을 반환합니다.

이제 제어는 +=작업자 에게 돌아갑니다 . 이제 작업을 완료하는 데 필요한 모든 정보가 있습니다. 결과를 저장할 위치 (의 저장 위치 i)와 이전 값을 알고 있으며 이전 값에 추가 할 값, 즉을 알고 있습니다 0. 따라서 i0으로 끝납니다.

Java와 마찬가지로 C #은 평가 순서를 수정하여 C 언어의 매우 비현실적인 측면을 삭제했습니다. 왼쪽에서 오른쪽, 상향식 : 코더가 예상 할 수있는 가장 명확한 순서입니다.


: +1 : 나는 기대 모든 코더 ... 나는 이런 식으로 뭔가와 동일 할 것으로 예상 것을 제외하고, 당신과 동의하지 SetSum(ref i, Inc(ref i))int SetSum(ref int a, int b) { return a += b; }int Inc(ref int a) { return a++; }나는 더 이상 그 기대 물론 ....
Miguel Angelo

또한, 내가 기대 한 것은 일치하지 않습니다! 그것은 동일하지 않을 Set(ref i, Sum(i, Inc(ref i)))int Set(ref int a, int b) { return a = b; }int Sum(int a, int b) { return a + b; }.
Miguel Angelo

감사; 내가 고쳐야 할 대답에 결함 / 불완전 함을 암시합니다.
Kaz

문제 SetSum는 왼쪽 피연산자를 평가하지 않고 i주소 만 취하므로 피연산자 의 전체 왼쪽에서 오른쪽 평가와 동일하지 않다는 것입니다. 같은 것이 필요합니다 SetSum(ref i, i, PostInc(ref i)). 의 두 번째 인수는 SetSum추가 할 값으로 i, 이전 값을 지정 하기 위해 사용합니다 i. SetSum그냥 int SetSum(ref int dest, int a, int b) { return dest = a + b; }입니다.
Kaz

할당 연산자가 오른쪽에서 왼쪽으로 평가하기 때문에 (예 : a = b = c = d) ++ 연산자와 혼동이 발생합니다 (예 : a = b = c = d). 원자 연산으로 (내 SetSum 방법으로했던 것처럼) ...하지만 실제로 발생하는 것은 C # a += ba = a + b... 로 변환 되어 + = 연산자가 원자가 아니라는 것을 보여줍니다 ... 단지 구문 설탕입니다.
Miguel Angelo

30

때문에 i++첫 번째 반환 값은, 다음을 증가시킵니다. 그러나 i가 1로 설정되면 다시 0으로 설정합니다.


17

증가 후 방법은 다음과 같습니다.

int ++(ref int i)
{
    int c = i;
    i = i + 1;
    return c;
}

따라서 기본적으로을 호출 i++하면 i증분이지만 원래 값은 0으로 반환됩니다.


12

간단한 답변

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;

12

i ++ 의미 : i의 값을 반환 한 다음 증가시킵니다.

i + = i ++ 의미 : i의 현재 값을 가져옵니다. i ++의 결과를 추가하십시오.

이제 시작 조건으로 i = 0을 추가합시다. i + = i ++는 이제 다음과 같이 평가됩니다.

  1. i의 현재 가치는 무엇입니까? 0입니다. i ++의 결과를 추가 할 수 있도록 저장하십시오.
  2. i ++ 평가 (현재 i 값이므로 0으로 평가)
  3. 저장된 값을로드하고 2 단계 결과를 추가하십시오. (0을 0으로 추가)

참고 : 2 단계의 끝에서 i의 값은 실제로 1입니다. 그러나 3 단계에서는 i 값이 증가하기 전에 i의 값을로드하여 삭제합니다.

i ++와 달리 ++ i는 증가 된 값을 반환합니다.

따라서 i + = ++ i는 1을 줄 것입니다.


그것은 도움입니다 Full
sonsha

11

사후 수정 증분 연산자 ( ++)는 변수에 표현식에 값을 제공 한 다음 증분 된 1을 덮어 쓰는 0을 반환 한 값을 i다시 증분하여 0을 얻습니다. ++ 연산자 (MSDN) 에서 증가 연산자에 대해 자세히 읽을 수 있습니다 .


8

i += i++;++나중에 수행하기 때문에 0과 같습니다 .

i += ++i; 전에 할거야


4
만약 그렇다면 ++그 후, 내가 기대했던 결과는 것입니다 1.
comecme

8

++ postfix는 i증분하기 전에 +=평가하고 i한 번만 평가 합니다.

따라서 i접미사 형식 ++이 사용 되므로 증분되기 전에 평가 및 사용되는 0 + 0 = 0 입니다. i먼저 증분 하려면 접두사 양식 ( ++i)을 사용하십시오 .

(또한 참고 사항 : 0 + (0 + 1) = 1이므로 1 만 가져와야 함)

참고 문헌 : http://msdn.microsoft.com/en-us/library/sa7629ew.aspx(+= )
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx(++ )


8

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 # 이하는 일을 설명 할뿐만 아니라 왜 많은 사람들이 나를 포함하여 혼동했는지 설명합니다.


2
이것을 원래 답변에 추가하십시오. 별도의 답변으로 제공해도 아무런 이점이 없습니다.
casperOne

2
디 컴파일 된 코드에 관한 것이기 때문에 다른 답변을 오염시키지 않기 위해 이것을했습니다 ...이 코드에서는 다른 접근법을 시도했습니다. 어떻게 생각해? 다른 답변을 편집 하고이 답변을 추가해야합니까? 어쩌면 이걸 앞에 붙이고 ... 모릅니다! 제안 해 주셔서 감사합니다!
Miguel Angelo

7

내가 항상 기억하는 좋은 니모닉은 다음과 같습니다.

뒤에++ 서 있으면 이전 값을 반환합니다 . 따라서 다음 코드

int a = 1;
int b = a++;

때문에, 1 인 a1을 하기 전에 그것이 증가되었다 ++ a . 사람들은이 포스트 픽스 표기법 이라고 부릅니다 . 사물이 정확히 반대 인 사전 수정 표기법 도 있습니다 . 만약 앞에++ 서 있으면 표현식 은 연산 후의 값을 반환합니다 .

int a = 1;
int b = ++a;

b 여기에 2입니다.

따라서 코드의 의미는

int i = 0;
i += (i++);

i++위에서 설명한대로 0을 반환하므로 0 + 0 = 0.

i += (++i); // Here 'i' would become two

Scott Meyers 는 "Effective C ++ programming"에서이 두 표기법의 차이점을 설명합니다. 내부적으로 i++(postfix)는 그 값 i을 기억하고 prefix-notation ( ++i)을 호출 하고 이전 값인을 반환합니다 i. 이것이 루프 ++i에서 항상 사용해야하는 이유입니다 for(모든 현대 컴파일러가 루프 에서 변환 i++되고 있다고 생각하지만 ).++ifor


1
테스트 int i = 0; i += (++i)했으며 i2가 아닌 1로 설정되었습니다. 그것은 당신이 작성하는 경우, 사실은 변경되지 않습니다 대신 접미사의 접두사를 사용하기 때문에, 너무 나에게 의미가 i += (++i)에게 i = i + (++i), (가) i이전에 평가 ++i의 결과로, i = 0 + (++i)궁극적를 i = 0 + 1.
Wutz

6

귀하의 질문에 대한 유일한 대답은 다음과 같습니다 .

좋아요, 모두 저를 태우기 전에 ..

당신은 모두 왜 i+=i++결과가 좋고 논리적 인지 대답 했습니다 i=0.

나는 당신의 대답의 각각 1 개마다 투표를하고 싶은 유혹을 받았지만 내가 계산 한 평판은 너무 높을 것입니다.

내가 왜 너 한테 화났어? 당신의 대답이 설명하기 때문이 아닙니다.
내가 읽은 모든 대답은 불가능을 설명하기 위해 놀랄만 한 노력을 다했습니다. 저는 박수를 보냅니다!

그러나 결과는 무엇입니까 ?? 직관적 인 결과입니까-수용 가능한 결과입니까?

여러분 각자는 "나체의 왕"을 보았고 어떻게 든 합리적 왕으로 받아 들였습니다.

당신은 모두 잘못입니다!

i+=i++;결과 0는 정의 되어 있지 않습니다.

당신이 .. 또는 심지어 더 나쁜 경우 언어 평가 메커니즘의 버그! 디자인의 버그.

증거를 원하십니까? 물론 당신이 원하는!

int t=0; int i=0; t+=i++; //t=0; i=1

이제 이것은 ... 직관적 인 결과입니다! 우리는 처음 t에 값으로 할당을 평가했기 때문에 평가와 할당 후에 만 ​​사후 작업이 발생했습니다. 합리적이지 않습니까?

다음 i=i++i=i같은 합리적 i입니까?

동안 t=i++t=i다른 결과가 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 #에 대한 문서를 찾지 못했습니다. 내가 찾은 것은 정반대입니다!

[ Postfix 증가 및 감소 연산자에 대한 MSDN 설명서에서 복사 : ++ 및- ]

접미사 연산자가 함수 인수에 적용되면 인수 값 이 함수로 전달되기 전에 증분되거나 감소 되지 않을 수 있습니다. 자세한 내용은 C ++ 표준의 1.9.17 단원을 참조하십시오.

그 말이 보장되지는 않습니다 ...

그 대답이 거만 해 보인다면 용서하십시오. 저는 거만하지 않습니다. 나는 단지 수천 명의 사람들이 여기에 와서 배우고 내가 읽은 대답이 그들을 오도하고 그들의 논리와 주제에 대한 이해를 해칠 것이라고 생각합니다.


100 %를 따르고 있는지 확실하지 않지만 C ++ 설명서를 참조하지만 제 질문은 C #에 관한 것입니다. 그 문서는 여기에 있습니다 .
피터

내 대답에서 C #을 언급하고있었습니다. 제공 한 링크에서 : x ++ 또는 x--의 결과는 연산 전의 x 값이고 ++ x 또는 --x의 결과는 연산 후 x의 값입니다. 두 경우 모두, 작업 후 x 자체는 동일한 값을 갖습니다. 테스트 할 때 그렇지 않다는 것을 분명히 보여줍니다 . i=++i왜냐하면와 다른 결과를 제공 할 것입니다 i=i++. 따라서 내 대답은 선다.
GY

Aha, 알았지 만 C ++ 설명서를 참조하면 혼란 스럽습니다. 그래서 당신이 말하는 것은 사양이 올바르게 구현되지 않았다는 것입니다.
Peter

아니요. 내 말은 사양에 따라 정의되어 있지 않으며 undefined를 사용하면 정의되지 않은 결과가 발생한다는 것입니다.
GY

C ++에서는 정의되지 않았지만 C #은 작업 후 동일한 값 이어야한다고 말합니다 . 그것은 정의되지 않은 것과 같지 않습니다 (그러나 나는 당신이 그것을 사용해서는 안되며, 내 면책 조항을보고, 나는 무슨 일이 일어나고 있는지 이해하려고 노력하고 있음에 동의합니다).
Peter

4

변수 뒤의 ++ 연산자는 접미사 증분을 만듭니다. 증분은 명령문의 다른 모든 것, 추가 및 할당 후에 발생합니다. 대신 변수 앞에 ++를 넣으면 i 값이 평가되기 전에 발생하고 예상되는 대답을 제공합니다.


2
++발생하지 않습니다 += 문, 그런 일 동안 의 실행 +=문. 이것이 ++get 의 효과가에 의해 재정의되는 이유 +=입니다.
dtb

++ i를 사용하면 실제로 2가 아닌 1이됩니다 (원래 '예상 답변').
피터

식의 사전 또는 사후 증가로 인해 할당 이 수정을 += 덮어 쓰는 것처럼 보입니다 .
Steven Lu

4

계산 단계는 다음과 같습니다.

  1. int i=0 // 0으로 초기화
  2. i+=i++ //방정식
  3. i=i+i++ // 컴파일러로 방정식을 단순화 한 후
  4. i=0+i++ // i 값 대체
  5. i=0+0 // i ++는 아래 설명과 같이 0입니다.
  6. i=0 // 최종 결과 i = 0

여기에서 처음에 값 i은 0입니다. WKT i++는 아무것도 아닙니다. 먼저 i값을 사용한 다음 i값을 1 씩 증가시킵니다 . 따라서 i값을 0으로 사용하고 계산 i++한 다음 1 씩 증가시킵니다. 따라서 값이됩니다. 0의.


3

두 가지 옵션이 있습니다.

첫 번째 옵션 : 컴파일러가 다음과 같이 명령문을 읽는 경우

i++;
i+=i;

결과는 2입니다.

에 대한

else if
i+=0;
i++;

결과는 1입니다.


5
어느 것도 실제 결과 가 아닙니다 .
Steven Lu

3

매우 조심하십시오 : C FAQ를 읽으십시오 : 당신이하려는 일 (지정과 ++같은 변수를 섞는 것 )은 지정되지 않을뿐만 아니라 정의되지 않습니다 (컴파일러가 평가 할 때 컴파일러가 아무것도 할 수 있음을 의미합니다 ! "합리적인"결과).

섹션 3을 읽으십시오 . 전체 섹션은 읽을 가치가 있습니다! 불특정의 의미를 설명하는 특히 3.9. 3.3 절은 "i ++"등으로 할 수있는 것과 할 수없는 것에 대한 간단한 요약을 제공합니다.

컴파일러 내부에 따라 0, 2, 1 또는 다른 것을 얻을 수 있습니다! 그리고 정의되지 않았으므로 그렇게해도됩니다.


oops, c # ... 나는 "gcc"에 의해 던져졌다. 일부는 코드를 분해하기 위해 갔다.
Olivier Dulac

1
나는 그것이 C # 인 것을 그리워했지만 어쨌든 대답을 좋아했습니다.
Iain 콜린스

1
@Iain : 감사합니다, 나도 그것의 가치, 많은 사람들이 알고 (또는하지 않는 대답이 가능 유지되었다 믿고 그것에 대해 subjcet에 대한 지식을 가진 대부분의 사람들이 동일한 가고 있었다 유즈넷의 가장 좋은 시간에서 자주 묻는 질문, )를 업데이트 할 장소
올리비에 Dulac에게

3

위의 답변에는 훌륭한 추론이 많이 있습니다. 작은 테스트를하고 당신과 공유하고 싶습니다.

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 ++가 추가하기 전에 실행할 수있는 이전의 경우와 달리 증가 연산자는 실행 경로에 오지 않습니다.

나는 이것이 약간 도움이되기를 바랍니다. 감사


2

C 프로그래밍 101 유형의 관점에서이 질문에 대답하기를 바라고 있습니다.

이 순서대로 진행되는 것처럼 보입니다.

  1. i는 0으로 평가되어 i = 0 + 0증가 작업이 i++"대기"상태가되지만 0에 대한 할당 i이 아직 발생하지 않았습니다.
  2. 증분이 i++발생합니다
  3. i = 0위 의 과제 가 발생하여 # 2 (사후 증가)가 수행 한 모든 작업을 효과적으로 덮어 씁니다.

이제 # 2는 실제로 아무 일도 일어나지 않을 것입니다 (아마 그렇지 않습니까?) 어느 쪽이든, 더 지식이 풍부한 다른 답변은 결과가 정확하고 C # 표준을 준수한다는 것을 보여 주지만 C / C ++에 대해 여기서 발생하는 것은 정의되지 않았습니다.

방법과 이유는 저의 전문 지식을 뛰어 넘지 만 이전에 평가 된 오른쪽 할당이 사후 증가 이후에 발생한다는 사실이 여기에 혼란을 줄 수 있습니다.

또한, 당신은 내가 믿는 ++i대신에 하지 않으면 결과가 2가 될 것으로 기대하지 않습니다 i++.


1
사전 증분 버전은 2C ++ 로 결과를 생성합니다 : ideone.com/8dH8tf
Steven Lu

말이 되네요 그러나 사전 증분은 증분 후보다 약간 덜 복잡한 상황입니다.
gkimsey 2014

2

간단히 말해서,

i ++는 "+ ="연산자가 완료된 후 "i"에 1을 추가합니다.

원하는 것은 ++ i이므로 "+ ="연산자가 실행되기 전에 "i"에 1을 더합니다.


0
i=0

i+=i

i=i+1

i=0;

그런 다음 1이에 추가됩니다 i.

i + = i ++

그래서 1을 추가하기 전에 i, i우리가 전에 하나를 추가 할 경우에만 0의 값을했다, i값 0을 얻는다.

i+=++i

i=2

-4

대답은 i입니다 1.

방법을 살펴 보자.

처음에는 i=0;.

그런 다음 i +=i++;값에 따라 계산하는 동안 과 같은 것이 0 +=0++;있으므로 연산자에 따라 우선 순위 0+=0가 먼저 수행되고 결과는 다음과 같습니다 0.

그런 다음 증가 연산자로서 적용 할 0++같이 0+1및의 값이 i될 것이다 1.


3
이 답변은 잘못되었습니다. 당신이 할 때 때문에 1을받지 않습니다 0 += 0++;할당이 증가 이후 ++하지만 값이 난의 이전 해석의 ++게시물 연산자이기 때문에 (.
PhoneixS

2
죄송하지만이 내용은 잘못되었습니다. 내 질문을 읽으면 결과가 0이라는 것을 알 수 있습니다. 코드를 실행하면 실제로 0이라는 것을 알 수 있습니다.
Peter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.