문제

며칠 뒤에 토론이있었습니다 여기 표현 여부에 대해

i = ++ i +1

UB (정의되지 않은 동작)를 호출 여부.

마지막으로 'I'의 값이 두 시퀀스 지점 사이에서 두 번 이상 변경되기 때문에 UB를 호출한다는 결론이 이루어졌습니다.

나는 토론에 관여했다 요하네스 샤브 같은 스레드에서. 그의 말에 따르면

i = (i, i ++, i) +1 ------ (1) / * UB도 호출 * /

나는 (1) 이전 하위 표현의 부작용이 Comma Operator ','I+ I ++ 사이, I ++와 i 사이에 대해 UB를 호출하지 않는다고 말했다.

그런 다음 그는 다음과 같은 설명을했습니다.

"예, I ++ 후 시퀀스 지점은 이전의 모든 부작용을 완료하지만 I ++의 부작용과 겹치는 할당 부작용을 중지하는 것은 없습니다.근본적인 문제는 과제의 부작용이 할당의 두 피연산자 모두의 평가 후 또는 이전에 발생하기 전에 발생하지 않으므로 시퀀스 포인트는 이것을 보호하는 것과 관련하여 아무것도 할 수 없다는 것입니다. 시퀀스 포인트는 부분 순서를 유도합니다. I ++ 후에 시퀀스 지점이 있습니다..

또한 시퀀스 지점은 아무것도 의미하지 않습니다. 평가 순서는 코드 형태로 지시되지 않습니다. 의미 론적 규칙에 따라 지시됩니다. 이 경우, 해당 피연산자의 피연산자 또는 하위 표현을 모두 평가하는 것과 관련하여 할당 부작용이 발생할 때 시맨틱 규칙은 없습니다. "

"Bold"로 작성된 성명서는 나를 혼란스럽게했다. 내가 아는 한:

"시퀀스 포인트라는 실행 시퀀스의 특정 지정된 지점에서, 이전 평가의 모든 부작용은 완료되어야하며, 후속 평가의 부작용은 이루어지지 않아야한다."

Comma 운영자는 또한 실행 순서를 지정하기 때문에 I ++의 부작용이 마지막에 도달하면 취소되었습니다. I.HE (Johannes)는 평가 순서가 지정되지 않았지만 (쉼표 운영자의 경우에는 잘 지정되어 있습니다. ).

그래서 나는 단지 (1) UB를 호출하는지 아닌지 알고 싶습니다. 누군가가 또 다른 유효한 설명을 할 수 있습니까?

감사!

도움이 되었습니까?

해결책

C 표준은 할당 연산자 (C90 6.3.16 또는 C99 6.5.16 할당 연산자)에 대해 말합니다.

왼쪽 피연산자의 저장된 값을 업데이트하는 부작용은 이전과 다음 시퀀스 지점 사이에서 발생해야합니다.

진술에서 나에게 :

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

할당 연산자에 대한 시퀀스 포인트 '이전'은 두 번째 쉼표 연산자이며 '다음'시퀀스 지점은 표현의 끝입니다. 그래서 표현이 정의되지 않은 동작을 호출하지 않는다고 말하고 싶습니다.

그러나이 표현 :

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

할당 연산자의 2 개의 피연산자 평가 순서가 정의되지 않았기 때문에 정의되지 않은 동작이있을 것입니다.이 경우에는 할당 연산자의 부작용이 발생할 때 문제가 아닌 문제가 아닌 문제는 값이 값을 모릅니다. 왼쪽 핸들에 사용 된 오른쪽에 사용됩니다. 오른쪽 전후에 평가됩니다. 이 평가 순서는 첫 번째 예에서는 발생하지 않습니다. 그 표현에서 값은 i 실제로 왼쪽에는 사용되지 않습니다. 할당 연산자가 관심을 갖는 것은 "lvalue-sness"입니다. i.

그러나 나는 또한이 모든 것이 충분히 스케치 적이라고 생각합니다 (그리고 관련된 뉘앙스에 대한 나의 이해는 충분히 스케치적일 것입니다) 누군가가 나를 (어느 쪽이든) 설득 할 수 있다면 놀라지 않을 것입니다.

다른 팁

나는 다음 표현이 확실히 정의되지 않은 행동을 가지고 있다고 믿는다.

i + ((i, i++, i) + 1)

그 이유는 쉼표 연산자가 괄호 안의 하위 표현 사이의 시퀀스 지점을 지정하지만 해당 시퀀스에서 왼손 피연산자의 평가를 지정하지 않기 때문입니다. + 발생합니다. 한 가지 가능성은 주변 순서 지점 사이에 있습니다 i++ 그리고 이것은 5/4 AS를 위반합니다 i 두 시퀀스 지점 사이에 기록되지만 동일한 시퀀스 지점 사이에서 두 번 읽습니다. 저장 할 값을 결정하는 것뿐만 아니라 첫 번째 피연산자의 값을 결정합니다. + 운영자.

이것은 또한 정의되지 않은 행동을 가지고 있습니다.

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

이제이 진술에 대해 확신이 없습니다.

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

같은 교장이 적용되지만 i 수정 가능한 lvalue로 "평가"되어야하며 언제든지 그렇게 할 수 있지만, 나는 그것의 것을 확신하지 못합니다. 지금까지 읽다 이것의 일부로. (또는 표현이 UB를 유발하도록 위반하는 또 다른 제한이 있습니까?)

하위 표현 (i, i++, i) 저장할 값을 결정하는 데있어 발생하며 해당 하위 표현은 값 저장 후 시퀀스 지점을 포함합니다. i. 나는 이것이 부작용을 요구하지 않는 방법을 보지 못합니다. i++ 저장 될 값을 결정하기 전에 완료되므로 할당 부작용이 발생할 수있는 최초의 가능한 지점.

이 Sequnce 지점 이후 i의 값은 최대 한 번만 읽히고 다시 저장 될 값을 결정하기 위해 만 읽습니다. i,이 마지막 부분은 괜찮습니다.

i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

정의되지 않은 행동을 불러 내지 않습니다. 의 부작용 i++ 다음 시퀀스 지점을 평가하기 전에 이루어지며,이 시퀀스 지점은 그 다음 시퀀스 지점을 따라와 할당하기 전에 쉼표로 표시됩니다.

그래도 좋은 언어 스도쿠. :-)

편집 :보다 정교한 설명이 있습니다 여기.

나는 Johannes (LITB) 진술에 관해 처음에 혼란 스러웠지만 그는 다음과 같이 언급했다.

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

<요하네스>
<a>가 할당이고 증분 인 경우. :s: 시퀀스 지점이면, 부작용은 시퀀스 점 사이의 다음과 같이 시퀀싱 될 수 있습니다. (i :s: i++< a ><n> :s: i) + 1. 스칼라의 값 i 여기서 첫 번째와 두 번째 시퀀스 지점 사이에서 두 번 변경되었습니다. 과제와 증분이 발생하는 순서는 지정되지 않으며, 그들 사이에는 시퀀스 지점이 없기 때문에 서로에 대한 원자도 아닙니다.이 부작용의 불특정 순서에 의해 허용되는 주문이 허용됩니다.

이것은 다릅니다 (i++, i++), 두 하위 표현의 평가 순서는 왼쪽에서 오른쪽에서 오른쪽으로 이루어지기 때문에 이전 평가의 증분이 완료되며 다음 증가는 아직 발생하지 않아야합니다. 이것은 가치의 변화가 없음을 강요합니다. i 두 시퀀스 점 사이 (i++, i++) 유효한
< /johannes>

이것은 C99에 따라 Litb가 언급 한 순서가 유효하지 않다고 생각하게 만들었습니다.

6.5.16.1 (2) 간단한 할당 (=)에서 오른쪽 피연산자의 값은 할당 표현식의 유형으로 변환되며 왼쪽 피연산자에 의해 지정된 물체에 저장된 값을 대체합니다.

즉, 오른쪽 피연산자의 값은 할당 부작용 전에 알려져야합니다 (좌측 피연산자에 해당하는 물체에 저장된 값의 수정).

6.5.17 (2) 쉼표 연산자의 왼쪽 피연산자는 무효 표현으로 평가됩니다. 평가 후 시퀀스 지점이 있습니다. 그런 다음 오른쪽 피연산자가 평가됩니다. 결과에는 유형과 가치가 있습니다.

즉, 쉼표 작동의 가장 오른쪽 피연산자는 쉼표 표현의 값과 유형 (및 내 예에 대한 오른쪽 피연산자의 값)을 알기 위해 평가되어야합니다.

따라서이 경우 할당 부작용에 대한 '이전 시퀀스 포인트'는 사실상 가장 올바른 쉼표 작업이 될 것입니다. 요하네스가 언급 한 가능한 순서는 유효하지 않습니다.

내가 틀렸다면 저를 바로 잡으십시오.


라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top