태그 보관물: language-lawyer

language-lawyer

쉼표가있는 삼항 연산자가 실제 경우에 하나의 표현식 만 평가하는 이유는 무엇입니까? 수행합니다. (someValue ? ++x,

저는 현재 C ++ Primer 책으로 C ++를 배우고 있으며이 책의 연습 중 하나는 다음과 같습니다.

다음 표현이 무엇을하는지 설명하십시오. someValue ? ++x, ++y : --x, --y

우리는 무엇을 압니까? 삼항 연산자가 쉼표 연산자보다 우선 순위가 높다는 것을 알고 있습니다. 이항 연산자를 사용하면 이해하기 쉬웠지만 삼항 연산자를 사용하면 약간 어려움을 겪고 있습니다. 이항 연산자를 사용하면 “더 높은 우선 순위를 갖는다”는 것은 우리가 더 높은 우선 순위로 표현식 주위에 괄호를 사용할 수 있으며 실행을 변경하지 않을 것임을 의미합니다.

삼항 연산자의 경우 다음을 수행합니다.

(someValue ? ++x, ++y : --x, --y)

컴파일러가 코드를 그룹화하는 방법을 이해하는 데 도움이되지 않는 동일한 코드를 효과적으로 생성합니다.

그러나 C ++ 컴파일러를 사용한 테스트를 통해 표현식이 컴파일된다는 것을 알고 있으며 :연산자가 그 자체로 무엇을 의미 할 수 있는지 알 수 없습니다 . 따라서 컴파일러는 삼항 연산자를 올바르게 해석하는 것 같습니다.

그런 다음 두 가지 방법으로 프로그램을 실행했습니다.

#include <iostream>

int main()
{
    bool someValue = true;
    int x = 10, y = 10;

    someValue ? ++x, ++y : --x, --y;

    std::cout << x << " " << y << std::endl;
    return 0;
}

결과 :

11 10

반면에 다음과 someValue = false같이 인쇄됩니다.

9 9

왜 C ++ 컴파일러는 삼항 연산자의 참 분기에 대해 증가하는 코드를 생성하고 삼항 x의 거짓 분기에 대해 x및 둘 다 감소시키는 이유는 y무엇입니까?

나는 심지어 다음과 같이 진정한 가지 주위에 괄호를두기까지했다.

someValue ? (++x, ++y) : --x, --y;

그러나 여전히 11 10.



답변

으로 @Rakete이 우수한 대답했다,이 까다 롭습니다. 나는 그것에 조금 더하고 싶습니다.

삼항 연산자는 다음과 같은 형식이어야합니다.

논리 또는 표현식 ? 표현식 : 할당 표현식

따라서 다음과 같은 매핑이 있습니다.

  • someValue: 논리 또는 표현
  • ++x, ++y: 표현
  • ??? 입니다 할당 표현은 --x, --y 또는 유일한 --x?

실제로 할당 표현식 은 쉼표로 구분 된 두 표현식으로 구문 분석 할 수 --x없기 때문에 (C ++의 문법 규칙에 따라) 할당 표현식 으로 취급 할 수 없습니다 .--x, --y

결과적으로 삼항 (조건부) 표현식 부분은 다음과 같습니다.

someValue?++x,++y:--x

가독성을 위해 괄호 안에있는 것처럼++x,++y 계산 되는 것으로 간주 하는 것이 도움이 될 수 있습니다 (++x,++y). ?와 사이에 포함 된 모든 항목 은 조건부 뒤에: 순서 가 지정됩니다. (나머지 게시물에서는 괄호로 묶습니다).

다음 순서로 평가됩니다.

  1. someValue?
  2. (++x,++y)또는 --x( bool1의 결과에 따라 )

이 표현식은 쉼표 연산자에 대한 왼쪽 하위 표현식으로 처리되며 오른쪽 하위 표현식은 다음 --y과 같습니다.

(someValue?(++x,++y):--x), --y;

즉, 왼쪽이 폐기 된 값 표현식 이므로 확실히 평가되지만 오른쪽을 평가하여 반환합니다.

그래서 무슨 일이 someValue있다 true?

  1. (someValue?(++x,++y):--x)실행하고 증가 x하고 y1111
  2. 왼쪽 표현식은 삭제됩니다 (증가의 부작용은 남아 있음).
  3. : 우리는 쉼표 연산자의 오른쪽 평가 --y후 감소 y가기10

행동 “수정”에, 당신은 그룹 수 --x, --y괄호는로 변환하는 주요 표현 이다 에 대한 유효한 항목을 지정 표현 * :

someValue?++x,++y:(--x, --y);

* 할당 식을 다시 기본 식으로 연결하는 다소 재미있는 긴 체인입니다 .

할당 표현식 — (다음으로 구성 될 수 있음)-> 조건식 -> 논리 또는 표현식 -> 논리 및 표현식 -> 포함 또는 표현식 -> 배타적 또는 표현식 – -> and-expression- > 같음-표현식 -> 관계형-표현식 -> shift-expression- > 가산 식 -> 곱셈-표현식 -> pm- 표현식 -> 캐스트-표현식 -> 단항 식 -> 접미사 식 -> 기본 식


답변

와, 까다 롭 네요.

컴파일러는 표현식을 다음과 같이 간주합니다.

(someValue ? (++x, ++y) : --x), --y;

삼항 연산자는를 필요로하고 :, 그 문맥에서 그 자체로 서있을 수는 없지만, 그 뒤에 쉼표가 거짓 케이스에 속해야하는 이유가 없습니다.

이제 그 결과를 얻는 이유가 더 이해할 수 있습니다. 경우 someValue사실, 다음 ++x, ++y그리고 --y효율적으로 변경하지 않는 실행받을 y만에 1을 추가합니다 x.

경우 someValue거짓, 다음 --x--y하나 둘을 감소시키는, 실행됩니다.


답변

C ++ 컴파일러가 삼항 연산자의 실제 분기에 대해서만 증가하는 코드를 생성하는 이유 x

당신은 무슨 일이 일어 났는지 잘못 해석했습니다. 참 분기는 xy. 그러나 y그 직후 무조건 감소합니다.

이것이 발생하는 방법은 다음과 같습니다 . 조건부 연산자가 C ++의 쉼표 연산자보다 우선 순위가 높기 때문에 컴파일러는 다음과 같이 표현식을 구문 분석합니다.

   (someValue ? ++x, ++y : --x), (--y);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^

--y쉼표 뒤 의 “분리 된”에 유의하십시오 . 이것이 y초기에 증가 된 감소로 이어지는 것 입니다.

나는 심지어 다음과 같이 진정한 가지 주위에 괄호를두기까지했다.

someValue ? (++x, ++y) : --x, --y;

올바른 경로에 있었지만 잘못된 분기를 괄호로 묶었습니다. 다음과 같이 else-branch를 괄호로 묶어이 문제를 해결할 수 있습니다.

someValue ? ++x, ++y : (--x, --y);

데모 (11 11 인쇄)


답변

문제는 삼항 표현식이 실제로 쉼표보다 우선 순위가 높지 않다는 것입니다. 사실, C ++는 단순히 우선 순위로 정확하게 설명 할 수 없으며, 정확히 3 항 연산자와 쉼표 사이의 상호 작용으로 분해됩니다.

a ? b++, c++ : d++

다음과 같이 취급됩니다.

a ? (b++, c++) : d++

(쉼표는 우선 순위가 더 높은 것처럼 작동합니다). 반면에

a ? b++ : c++, d++

다음과 같이 취급됩니다.

(a ? b++ : c++), d++

삼항 연산자가 더 높은 우선 순위입니다.


답변

답변에서 간과 된 요점은 (주석에 언급되었지만) 조건부 연산자는 변수에 두 값 중 하나를 할당하는 지름길로 실제 코드에서 변함없이 사용된다는 것입니다 (설계에 의해 의도 되었습니까?).

따라서 더 큰 컨텍스트는 다음과 같습니다.

whatIreallyWanted = someValue ? ++x, ++y : --x, --y;

얼굴에 터무니없는 일이므로 범죄는 다양합니다.

  • 언어는 과제에서 어리석은 부작용을 허용합니다.
  • 컴파일러는 당신이 이상한 일을하고 있다는 경고를하지 않았습니다.
  • 이 책은 ‘속임수’질문에 초점을 맞추고있는 것으로 보입니다. 뒤에있는 대답이 “이 표현이하는 일은 아무도 예상하지 못한 부작용을 생성하기 위해 고안된 예에서 이상한 가장자리 사례에 의존하는 것입니다. 절대 이렇게하지 마십시오.”라는 대답을 바랄 수 있습니다.

답변