[C#] 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)의 경우 :

  1. x는 변수를 생성하기 위해 평가됩니다
  2. 변수 값이 임시 위치에 복사됩니다
  3. 임시 값이 증가하여 새 값을 생성합니다 (임시 값을 덮어 쓰지 않음).
  4. 새로운 값은 변수에 저장됩니다
  5. 연산 결과는 새로운 값 (즉, 임시 값의 증가 된 값)입니다.

접미사 형식 (x ++)의 경우 :

  1. x는 변수를 생성하기 위해 평가됩니다
  2. 변수 값이 임시 위치에 복사됩니다
  3. 임시 값이 증가하여 새 값을 생성합니다 (임시 값을 덮어 쓰지 않음).
  4. 새로운 값은 변수에 저장됩니다
  5. 작업 결과 는 임시 값입니다.

알아 두어야 할 사항 :

첫째, 이벤트의 순서는 두 경우 모두 동일합니다 . 다시 말하지만, 시간의 이벤트 순서가 접두사와 접두사 사이 에서 변경 되는 경우 는 절대 아닙니다 . 평가가 다른 평가 전에 또는 다른 평가 후에 발생한다고 말하는 것은 전적으로 거짓입니다. 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

첫 번째 테스트 currentValue에서 TestMethod()확장 프로그램 에 전달 된 내용과 확장 프로그램 에 전달 된 내용이 예상대로 동일한 값을 표시 한다는 것을 알 수 있습니다 .

그러나 두 번째 경우 에는을 호출 한 후currentValue 발생률 이 증가했음을 알리려고 하지만 결과에서 볼 수 있듯이 ‘현재 : 2’결과에 표시된대로 호출 전에 발생합니다.TestMethod()

이 경우 먼저 값이 currentValue임시에 저장됩니다. 다음으로, 그 값의 증분 버전은 currentValue원래 값을 저장하는 임시 값을 건드리지 않고 다시 저장됩니다 . 마지막으로 임시가에 전달됩니다 TestMethod(). 호출 증가가 발생하면 증가 TestMethod()하지 않은 동일한 값을 두 번 쓰지만 그렇지 않습니다.

currentValue++++currentValue연산 에서 반환 된 값은 두 연산이 모두 종료 될 때 변수에 저장된 실제 값이 아니라 임시 값을 기반으로 한다는 점에 유의해야합니다 .

위의 순서대로 상기 첫 두 단계는 변수의 현재 값을 임시로 복사합니다. 이것이 반환 값을 계산하는 데 사용되는 것입니다. 접두사 버전의 경우 임시 값이 증가하는 반면 접미사 버전의 경우 직접 / 증가되지 않는 값입니다. 변수 자체는 초기 저장 후 임시로 다시 읽지 않습니다.

간단히 말해, 접미사 버전은 변수에서 읽은 값 (예 : 임시 값)을 반환하고 접두사 버전은 변수에 다시 쓴 값 (예 : 임시 값 증가)을 반환합니다. 변수 값을 반환하지 마십시오.

변수 자체가 변동적일 수 있고 다른 스레드에서 변경 되었기 때문에 이러한 연산의 반환 값이 변수에 저장된 현재 값과 다를 수 있으므로 이해해야합니다.

사람들이 우선 순위, 연관성 및 부작용이 실행되는 순서에 대해 매우 혼란스러워하는 것은 놀랍게 일반적입니다. C에서는 매우 혼란 스럽기 때문에 주로 의심됩니다. 접두사와 접미사 작업이 “시간에 물건을 움직인다”는 아이디어의 허위를 보여주는 것을 포함하여 이러한 문제에 대한 추가 분석은 다음을 참조하십시오.

https://ericlippert.com/2009/08/10/precedence-vs-order-redux/

이 SO 질문으로 이어졌습니다.

int [] arr = {0}; int 값 = arr [arr [0] ++]; 값 = 1?

주제에 대한 이전 기사에 관심이있을 수도 있습니다.

https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/

https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/

C가 정확성에 대해 추론하기 어려운 흥미로운 경우 :

https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited

또한 연결 간단한 할당과 같이 부작용이있는 다른 작업을 고려할 때 비슷한 미묘한 문제가 발생합니다.

https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple

다음은 증가 연산자 가 변수가 아닌 C #의 을 만드는 이유에 대한 흥미로운 게시물입니다 .

C와 같은 언어로 ++ i ++를 할 수없는 이유는 무엇입니까?


답변

당신이 가지고 있다면:

int i = 10;
int x = ++i;

다음 x이 될 것입니다 11.

그러나 당신이 가지고 있다면 :

int i = 10;
int x = i++;

다음 x이 될 것입니다 10.

Eric이 지적했듯이 두 경우 모두 증분이 동시에 발생하지만 결과는 다른 값으로 제공됩니다 (Eric! 덕분에).

일반적으로, ++i정당한 이유가없는 한 사용하고 싶습니다 . 예를 들어 루프를 작성할 때 다음을 사용하고 싶습니다.

for (int i = 0; i < 10; ++i) {
}

또는 변수를 늘려야하는 경우 다음을 사용하고 싶습니다.

++x;

일반적으로 한 가지 방법은 다른 의미가 없으며 코딩 스타일에 의존하지만 다른 할당 (내 원래 예제와 같이)에서 연산자를 사용하는 경우 잠재적 부작용을 인식하는 것이 중요합니다.


답변

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.

이 질문에 대답합니까?


답변

연산자가 작동하는 방식은 동시에 증가하지만, 변수보다 앞에 있으면 증가 / 감소 된 변수로 표현식이 평가됩니다.

int x = 0;   //x is 0
int y = ++x; //x is 1 and y is 1

변수 뒤에있는 경우, 현재 명령문은 마치 증가 / 감소되지 않은 것처럼 원래 변수로 실행됩니다.

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

필요하지 않은 경우 사전 증가 / 감소 (++ x) 사용에 dcp에 동의합니다. 실제로 증가 후 / 감소를 사용하는 유일한 시간은 while 루프 또는 해당 종류의 루프입니다. 이 루프는 동일합니다 :

while (x < 5)  //evaluates conditional statement
{
    //some code
    ++x;       //increments x
}

또는

while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
    //some code
}

배열을 색인화하는 동안이 작업을 수행 할 수도 있습니다.

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


답변

레코드의 경우 C ++에서 (예를 들어) 작업 순서를 신경 쓰지 않으면 (즉, 증가 또는 감소하고 나중에 사용하려는 경우) 접두사 연산자는 더 효율적이지 않기 때문에 더 효율적입니다. 개체의 임시 복사본을 만들어야합니다. 불행히도 대부분의 사람들은 접두사 (++ var) 대신 posfix (var ++)를 사용합니다. 왜냐하면 우리가 처음에 배웠기 때문입니다. (나는 인터뷰에서 이것에 대해 물었다). 이것이 C #에서 사실인지 확실하지 않지만 그럴 것이라고 가정합니다.


답변