정의되지 않은 동작 및 시퀀스 포인트에 대한 이 답변을 읽은 후 작은 프로그램을 작성했습니다.
#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)
로 평가된다
i
, void 표현식으로 평가되고 값이 삭제됩니다.++i
, void 표현식으로 평가되고 값이 삭제됩니다.- 마지막으로
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의 과거에는 인라인 기능이 없었으므로 호출 오버 헤드를 피할 수 있습니다.