2009-08-11 5 views
12

오늘 저는 Eric Lippert에 의해 십자가를 냈습니다. 여기서 그는 사업자 우선 순위와 평가 순서 사이의 신화를 없애려고했습니다. 내가 변수 값의 값을 생각하면
int [] arr = {0}; int 값 = arr [arr [0] ++]; 값 = 1?

 int[] arr = {0}; 
     int value = arr[arr[0]++]; 

지금, 나는 단순히 하나 그것을 계산 : 끝에서 나를 혼란있어이 개 코드 조각이 있었다, 여기에 첫 번째 조각이다. 어떻게 작동하는지 생각 해보자. 그 안에 하나 개의 항목 INT 의 배열로서

  1. 먼저 도착 선언; 이 항목의 값은 0입니다.
  2. 두 번째는 에 arr [0] --0의 값을 가져옵니다.
  3. 셋째 도착 (여전히 0) [공정 (2)의 값 ]의 값이 [0]이 0으로 다시 --still
  4. 네번째 단계의 값을 할당 도착을 얻을 --gets 3 (0)를 변수 값에 적용합니다. --value = 0 해주기
  5. 2 1 --Now 도착 [0] = 1

명백하게이 잘못 스텝의 값에 추가. 실제로 증가가 언제 발생하는지에 대한 명시적인 진술을 위해 C# 스펙을 검색하려고 시도했지만 아무 것도 찾지 못했습니다. 현재 이곳에

int[] data = { 11, 22, 33 }; 
int i = 1; 
data[i++] = data[i] + 5; 

나는이 프로그램이 배열을 선언하고 난에 1을 할당 --after 실행할 생각하는 방법은 다음과 같습니다
두 번째 조각은 주제에 에릭의 blog post의 코멘트에서입니다.

  1. 얻기 데이터 [PLZ 참아 [I]는 --1
  2. 는 단계 1 값 데이터 5 --6
  3. 할당 [I] (값 추가 단계의 또 1) 2 값 --data [내가] = 6
  4. 단위 I - I = 2

내 이해에 따르면,이 배열은 현재 값 {11 (27)를 포함한다, 33}. 그러나 배열 값을 인쇄하기 위해 반복했을 때 : {11, 38, 33}. 즉 게시 증가가 배열을 참조 해제하기 전에 발생했음을 의미합니다!
어째서? 이 게시물 증가가 게시물이 아닌가요? 즉 다른 모든 일 후에 발생합니다.
내가 뭘 놓친거야?

+0

다섯 번째 단계로 명세서 생각해야하는 것은 어쨌든 올바르지 않습니다. "2 단계 1의 값에 더하기 - 이제 arr [0] = 1" 배열에서 가져 오거나 복사 한 값은 1 씩 증가하지만 ** 배열의 ** 값은 변경되지 않습니다. 따라서 구문 arr [0] = 1은 false입니다. 5 단계에서 arr [0] = 1로 복사 된 값. – Gertjan

+0

그럼 코드를 실행하고 첫 번째 대답에는 0을, 두 번째에는 {11,27,33}의 값을 얻었습니다.이 문제는 컴파일러에 따라 다릅니다 ? – bubblegum

+1

@Swabha 확실히 C#을 사용하고 있습니까? – Galilyou

답변

16

사후 증가 연산은 전체 식을 계산할 때 발생합니다. 값이 계산 된 후 다른 표현식이 평가되기 전에 발생하는 부작용입니다.즉

, 어떤 표현 E에 대한, E ++ (합법적 인 경우) (의사 코드) 같은 것을 나타냅니다 아무것도를 평가하기 전에, + + E를 평가하는 모든 일부

T tmp = E; 
E += 1; 
return tmp; 

.

자세한 내용은 7.5.9 절을 참조하십시오.


은 또한, LHS (이 경우에서와 같이) 가변으로 분류 할당 작업은 LHS는 RHS가 평가
전에 을 평가한다. 그래서 예에서

:

int[] data = { 11, 22, 33 }; 
int i = 1; 
// Work out what the LHS is going to mean... 
int index = i; 
i++; 
// We're going to assign to data[index], i.e. data[1]. Now i=2. 

// Now evaluate the RHS 
int rhs = data[i] + 5; // rhs = data[2] + 5 == 38 

// Now assign: 
data[index] = rhs; 

이에 대한 사양의 관련 비트 섹션 7.16.1 (C# 3.0 사양)입니다 :

int[] data = { 11, 22, 33 }; 
int i = 1; 
data[i++] = data[i] + 5; 

은 동일합니다.

+3

그와, 표현식 (할당 포함)은 연산자 우선 순위가 다른 것을 지시 할 때를 제외하고는 왼쪽에서 오른쪽으로 평가됩니다. 따라서 데이터 [i ++] (과제의 왼쪽 편)는 오른쪽에있는 데이터 [i]보다 먼저 평가됩니다. – LBushkin

+0

@LBushkin : 나는 당신이 논평하는 동안 정확히 그 목적을 위해 편집하고 있었다고 생각합니다. –

+0

@LBushkin Wrong. Microsoft는 할당 (=) 연산자와 3 진 (? :) 연산자가 모두 오른쪽에서 왼쪽으로 처리된다는 것을 명시 적으로 말합니다. –

2
data[i++] // => data[1], then i is incremented to 2 

data[1] = data[2] + 5 // => 33 + 5 
+0

나는 당신과 의견이 다릅니다. 구현에서는 할당 연산자가 우선 순위가 가장 낮으며 오른쪽에서 왼쪽으로 처리됩니다. 그 사람은 언어 사양에 따라 그의 가정에 맞다. http://msdn.microsoft.com/en-us/library/aa691323(VS.71).aspx –

+2

@Leahn Novash : 사용자는 다시 평가 순서와의 연관성을 혼동합니다. "a = b = c"는 오른쪽 연관 "a = (b = c)"이지만 평가 순서에 대해서는 아무 것도 말하지 않습니다. C#의 평가 순서는 항상 왼쪽에서 오른쪽입니다. – Daniel

+0

사양을 더 자세히 읽었습니다. 나는 교정했다. –

-4

일부 컴파일러는 i ++가 ++ i가되도록 최적화 할 수 있습니다. 대부분의 경우 최종 결과는 동일하지만 컴파일러가 잘못된 경우가 드문 경우 중 하나입니다.

지금 Visual Studio에 액세스 할 수 없지만 코드 최적화를 비활성화하고 결과가 동일하게 유지되는지 확인하십시오.

+4

i ++와 ++ i는 다르고 다른 방식으로 사용됩니다. i ++를 ++로 변환 한 컴파일러는 많은 개발자의 분노를 불러 일으킬 것입니다. – NickAldwin

+1

다행히도 C#은 이보다 나은 행동을 정의합니다. –

+1

컴파일러, gitter 또는 프로세서 최적화가 발생할 수 있다는 것에 동의하지만, 단일 스레드 응용 프로그램에서 최적화 결과 만 원하는 결과와 구별 할 수없는 경우이 문제가 발생합니다. http://blogs.msdn.com/ericlippert /archive/2009/08/10/precedence-vs-order-redux.aspx – Galilyou

0

사후 증가 연산자는 값이 사용 된 후에 변수를 증가시킬 것으로 예상됩니다. 이 경우 변수는 변수에 대한 두 번째 참조 전에 증가됩니다. 그렇게하지 않을 것입니다 경우 실제로 아무것도하지 않기 때문에 말, 당신은 내가보고 지시에, 증가 연산자를 제거 할 수 것처럼 될 경우

data[i++] = data[i++] + data[i++] + data[i++] + 5 

를 작성할 수

.

제 니펫
5

시퀀스이다 : 당신 같은

  1. 선언 도착 설명 :
  2. 가 도착의 값을 검색 [0], 도착의 [0의 값 단위 0
  3. 인 1.
  4. 에 도착 된 [도착의 값이다 (# 2의 결과)를 검색 [0], 이는 (# 3마다) value 결과 1.
  5. 스토어이다.
  6. 값 = 제 1
  7. 니펫

이 평가는 아직 왼쪽에서 오른쪽이다.

  1. 여기서 결과를 저장하고 있습니까? 데이터 [i ++]에서 데이터 [1]이지만 지금은 i = 2
  2. 무엇을 추가하고 있습니까?data [i] +5는 현재 데이터 [2] +5이며, 38입니다.

누락 된 부분은 "게시물"이 "그 밖의 모든 후"를 의미하지 않는다는 것입니다. "변수의 현재 값을 검색 한 직후"를 의미합니다. "코드 라인"의 중간에 일어나는 게시물 증가는 완전히 정상입니다.

0

당신은 세 단계로 할당 생각해야 :

  1. 것은 왼쪽 평가 (= 값을 저장해야합니다 주소를 얻을)
  2. 하는 평가 오른쪽
  3. 단계에서 값을 지정을 1 단계

에서 메모리 위치 2는

같은이있는 경우

그런 다음 A()가 먼저 실행 된 다음 C()가 실행되고 속성 설정자 B가 실행됩니다.

기본적으로, 당신은

StoreInArray(data, i++, data[i] + 5); 
관련 문제