[c] i = (i, ++ i, 1) + 1은 무엇입니까? 하다?

정의되지 않은 동작 및 시퀀스 포인트에 대한 이 답변을 읽은 후 작은 프로그램을 작성했습니다.

#include <stdio.h>

int main(void) {
  int i = 5;
  i = (i, ++i, 1) + 1;
  printf("%d\n", i);
  return 0;
}

출력은 2입니다. 오 하나님, 나는 감소가 오는 것을 보지 못했습니다! 여기서 무슨 일이 일어나고 있습니까?

또한 위의 코드를 컴파일하는 동안 경고 메시지가 나타납니다.

px.c : 5 : 8 : 경고 : 쉼표 식의 왼쪽 피연산자는 효과가 없습니다.

  [-Wunused-value]   i = (i, ++i, 1) + 1;
                        ^

왜? 그러나 아마도 첫 번째 질문에 대한 답변으로 자동 응답 될 것입니다.



답변

식에서 (i, ++i, 1)쉼표는 쉼표 연산자입니다.

쉼표 연산자 (token으로 ,표시됨)는 첫 번째 피연산자를 평가하고 결과를 버린 다음 두 번째 피연산자를 평가하여이 값 (및 유형)을 리턴하는 2 진 연산자입니다.

첫 번째 피연산자가 삭제되므로 일반적으로 첫 번째 피연산자가 바람직한 부작용을 갖는 경우에만 유용합니다 . 첫 번째 피연산자에 대한 부작용이 발생하지 않으면 컴파일러는 아무런 영향없이 표현식에 대한 경고를 생성 할 수 있습니다.

따라서 위의 식에서 가장 왼쪽 i이 평가되고 해당 값이 삭제됩니다. 그런 다음 ++i평가 i되고 1 씩 증가 하고 식의 값은 ++i무시 되지만 부작용 i은 영구적 입니다. 그런 다음 1평가되고 표현식의 값은입니다 1.

그것은

i;          // Evaluate i and discard its value. This has no effect.
++i;        // Evaluate i and increment it by 1 and discard the value of expression ++i
i = 1 + 1;  

참고 상기 식 완벽 유효하고 정의되지 않은 동작 호출하지 않는 있기 때문에 순서 포인트 콤마 연산자의 좌우 피연산자의 평가 사이가.


답변

C11, 챕터 6.5.17, 쉼표 연산자 인용

쉼표 연산자의 왼쪽 피연산자는 void 표현식으로 평가됩니다. 평가와 올바른 피연산자의 평가 사이에는 순서 점이 있습니다. 그런 다음 올바른 피연산자가 평가됩니다. 결과 유형과 값이 있습니다.

따라서 귀하의 경우에는

(i, ++i, 1)

로 평가된다

  1. i, void 표현식으로 평가되고 값이 삭제됩니다.
  2. ++i, void 표현식으로 평가되고 값이 삭제됩니다.
  3. 마지막으로 1값이 반환되었습니다.

그래서 마지막 문장은

i = 1 + 1;

i도착합니다 2. 나는 이것이 당신의 두 질문에 모두 대답한다고 생각합니다.

  • i값 2는 어떻게 얻습니까?
  • 경고 메시지가 나타나는 이유는 무엇입니까?

참고 : FWIW, 왼쪽 피연산자 평가 후 시퀀스 포인트(i, ++i, 1)있으므로 일반적으로 실수로 생각할 수 있으므로 UB를 호출하지 않습니다 .


답변

i = (i, ++i, 1) + 1;

단계별로 분석해 봅시다.

(i,   // is evaluated but ignored, there are other expressions after comma
++i,  // i is updated but the resulting value is ignored too
1)    // this value is finally used
+ 1   // 1 is added to the previous value 1

그래서 우리는 2를 얻습니다. 그리고 마지막 과제는 :

i = 2;

지금 덮어 쓰기 전에 i에 있던 것이 무엇이든간에 .


답변

의 결과

(i, ++i, 1)

이다

1

에 대한

(i,++i,1) 

평가는 ,운영자가 평가 된 값을 버리고 가장 정확한 값을 유지하도록 수행됩니다.1

그래서

i = 1 + 1 = 2


답변

쉼표 연산자 에 대한 위키 페이지에서 유용한 정보를 찾을 수 있습니다.

기본적으로

… 첫 번째 피연산자를 평가하고 결과를 버린 다음 두 번째 피연산자를 평가하고이 값 (및 유형)을 반환합니다.

이것은

(i, i++, 1)

차례로 평가합니다 i, 그 결과를 폐기, 평가하고 i++, 그 결과를 폐기하고 평가하고 반환 1.


답변

쉼표 연산자가 무엇을하고 있는지 알아야합니다.

당신의 표현 :

(i, ++i, 1)

첫 번째 표현식 ( i)이 평가되고 두 ​​번째 표현식 ( ++i)이 평가되며 세 번째 표현식 ( 1)이 전체 표현식에 대해 리턴됩니다.

결과는 다음과 같습니다 i = 1 + 1.

보너스 질문의 경우 첫 번째 표현 i은 전혀 효과가 없으므로 컴파일러가 불평합니다.


답변

쉼표에는 ‘역’우선 순위가 있습니다. IBM의 오래된 서적과 C 매뉴얼 (70s / 80s)에서 얻을 수 있습니다. 따라서 마지막 ‘명령’은 부모 표현식에 사용되는 것입니다.

현대 C에서는 그 사용이 이상하지만 오래된 C (ANSI)에서는 매우 흥미 롭습니다.

do {
    /* bla bla bla, consider conditional flow with several continue's */
} while ( prepAnything(), doSomethingElse(), logic_operation);

모든 연산 (함수)이 왼쪽에서 오른쪽으로 호출되지만 조건부 ‘while’의 결과로 마지막 식만 사용됩니다. 이것은 ‘goto’의 처리가 조건 점검 전에 실행되는 고유 한 명령 블록을 유지하는 것을 방지합니다.

편집 : 왼쪽 피연산자의 모든 논리를 처리 할 수있는 논리 함수를 호출하지 않으므로 논리 결과를 반환합니다. C의 과거에는 인라인 기능이 없었으므로 호출 오버 헤드를 피할 수 있습니다.