함수 - C++ 11에서`i+=++ i+1`은 정의되지 않은 동작을 나타 냅니까?




이펙티브 c++ 정리 (4)

이 질문은 제가 읽는 동안 나타났습니다 (답변) 그래서 C ++ 11에서 잘 정의 된 i = ++ i + 1입니까?

나는 (1) ++i 가 lvalue를 반환하지만 + 가 prvalues를 피연산자로 취하므로 lvalue에서 prvalue 로의 변환이 수행되어야한다는 미묘한 설명이 있다는 것을 모았습니다. 이것은 lvalue ( i 의 이전 값보다 하나가 아닌)의 현재 값을 얻는 것을 포함하므로 증분 (즉, i 업데이트)의 부작용 후에 시퀀스를 지정해야합니다 (2) 할당의 LHS도 또한 따라서 값 평가는 i 의 현재 값을 가져 오는 것을 포함하지 않습니다. (3) 할당 자체의 값 계산은 i (다시)를 업데이트하는 것을 포함하지만 그 RHS의 값 계산 후에 순서가 정해지며, 따라서 RHS의 값 계산 후에 순서가 결정됩니다. i 순전 한 업데이트; 문제 없어.

좋아, 거기에 UB가 없다. 이제 내 질문은 사람이 부양 연산자를 = 에서 += (또는 유사한 연산자)로 변경하면 어떻게 될까요?

표현 i += ++i + 1 의 평가가 정의되지 않은 행동을 유도합니까?

내가 본 것처럼, 표준은 여기에 모순되는 것처럼 보인다. += 의 LHS가 여전히 lvalue (그리고 그 RHS가 여전히 prvalue)이기 때문에, (1)과 (2)에 관한 한 동일한 추론이 적용됩니다. += 의 피연산자 평가에서 정의되지 않은 동작은 없습니다. (3)에 관해서는, 복합 할당 += (더 정확하게는 그 연산의 부작용, 필요한 경우 그 값 계산은 부작용 후에 어떤 순서로든 수행됨) 이제는 i 의 현재 값을 가져와야합니다 , 그리고 나서 (분명하게 표준이 그렇게 명시 적으로 말하지 않더라도, 그렇지 않으면 그러한 연산자의 평가는 항상 정의되지 않은 행동을 호출 할 것이다) RHS를 추가하고 그 결과를 다시 i 저장하라. 이 두 연산은 모두 ++ 의 부작용에 대해 순서가 지정되지 않았지만 위에 논한 것처럼 정의되지 않은 동작을 제공합니다 ( ++ 의 부작용은 += 연산자의 RHS를주는 + 값 계산 전에 순서가 지정됩니다. 어떤 값 계산이 그 화합물 할당의 연산 이전에 순서가 정해진 다), 그렇지 않다.

그러나 한편으로 표준은 E += FE = E + F 와 같다고 말합니다. 단, (왼쪽 값) E는 단 한 번만 계산된다는 점만 다릅니다. 이제 우리 예제에서 i 의 값 계산 (이것은 E 가 여기에 있습니다) 은 lvalue 가 다른 작업을 순서화해야하는 것을 포함하지 않으므로 한 번 또는 두 번 수행하면 아무런 차이가 없습니다. 우리의 표현은 E = E + F 와 정확히 동일해야합니다. 그러나 여기에 문제가 있습니다. i = i + (++i + 1) 것이 정의되지 않은 동작을 제공한다는 것은 꽤 명백합니다! 뭐라 구요? 아니면 표준의 결함입니까?

추가됨. 위의 논의를 약간 수정하여 부작용과 가치 계산 간의 적절한 구분을 정당화하고 두 가지 모두를 포괄하는 표현식의 "평가"(표준과 동일)를 사용합니다. 내 주요 질문은 행동이 정의되어 있는지 아닌지에 대한 것이 아니라 어떻게 결정해야하는지에 대한 표준을 읽어야하는 방법에 관한 것입니다. 주목할만한 것은, 복합 할당 연산의 의미에 대한 궁극적 인 권위로서 E op= F 의 등가성을 E = E op F 로 취해야한다는 것인데 (이 경우 예제는 분명히 UB를 가짐), 또는 단순히 수학 연산 은 할당 할 값 (즉, op 식별되는 값)을 결정하는 것과 관련됩니다. 왼쪽 값과 오른쪽 값은 복합 대입 연산자의 LHS를 왼쪽 피연산자로, 오른쪽 RHS를 오른쪽 피연산자로 변환합니다. 후자의 선택은이 예에서 UB를 주장하는 것이 훨씬 어렵게 만듭니다. 나는 동등성을 권위있게 만드는 것을 유혹하고있다 (그래서 복합 할당은 제 2 급 프리미티브의 일종이되고, 그 의미는 일류 프리미티브의 용어로 다시 쓰여지므로 언어 ​​정의가 단순화 될 것이다). 이것에 대한 오히려 강한 주장이다.

  • " E 는 단 한 번만 평가됩니다"예외 때문에 동등성은 절대적이지 않습니다. 이 예외는 E 의 평가가 부작용이 정의되지 않은 행동을 포함하는 경우, 예를 들어 상당히 일반적인 a[i++] += b; 경우에는 사용하지 않는 것이 중요합니다 a[i++] += b; 용법. 사실 나는 화합물 배정을 제거하기 위해 절대적으로 동등한 재 작성이 가능하다고 생각하지 않는다. 가상의 ||| 연산자를 사용하여 순서가없는 평가를 지정하면 E op= F; (단순화를 위해 int 피연산자와 함께) { int& L=E ||| int R=F; L = L + R; } { int& L=E ||| int R=F; L = L + R; } { int& L=E ||| int R=F; L = L + R; } 하지만 예제에는 더 이상 UB가 없습니다. 어쨌든 표준은 우리에게 다시 작성법을 제공하지 않습니다.

  • 이 표준은 복합어 할당을 의미론에 대한 별도의 정의가 필요하지 않은 제 2 급 프리미티브로 취급하지 않습니다. 예를 들어, 5.17 (강조 광산)

    대입 연산자 (=)와 복합 대입 연산자는 모두 오른쪽에서 왼쪽으로 그룹화됩니다. [...] 모든 경우 에 할당은 오른쪽 및 왼쪽 피연산자의 값 계산 후에 할당 식의 값 계산 전에 순서가 지정됩니다. 불확정 시퀀스 된 함수 호출과 관련하여 , 복합 할당의 연산은 단일 평가 입니다.

  • 복합 과제를 간단한 과제로 단순하게 단축하려는 의도가있는 경우이 설명에 명시 적으로 포함시킬 이유가 없습니다. 최종 문구는 심지어 동등성이 권위있는 것으로 간주되는 경우에 해당 될 수있는 것과 직접적으로 모순됩니다.

화합물 할당이 그들 자신의 의미론을 가지고 있다는 것을 인정한다면, 평가는 (수학적 조작과는 별도로) 단지 부수 효과 (과제)와 가치 평가 (과제 후에 순서 화됨) 이상을 포함한다는 점이 발생한다. 또한 LHS의 (이전) 값을 가져 오는 무명 조작. 이것은 보통 "lvalue-to-rvalue conversion"의 제목으로 다루지 만, LHS 를 rvalue 피연산자 취하는 연산자가 없으므로 여기에서 그렇게하는 것이 합당하지 않습니다 (확장 된 "동등한"형식). ++ 의 부작용과 잠재적 인 순서가없는 관계로 인해 UB가 발생하는 것은이 무명 조작입니다. 그러나이 무순위 관계는 이름없는 조작이 아니기 때문에 표준에 명시 적으로 명시되어 있지 않습니다. 바로 그 존재가 표준에 함축되어있는 작업을 사용하여 UB를 정당화하는 것은 어렵습니다.


예, 그것은 UB입니다!

표현의 평가

i += ++i + 1

다음 단계를 진행하십시오.

5.17p1 (C ++ 11) 상태 (강조 표시) :

대입 연산자 (=)와 복합 대입 연산자는 모두 오른쪽에서 왼쪽으로 그룹화됩니다. 모두 왼쪽 피연산자로 수정 가능한 좌변 치를 필요로하고 왼쪽 피연산자를 참조하는 좌변 치를 반환합니다. 왼쪽 피연산자가 비트 필드이면 모든 경우의 결과는 비트 필드입니다. 모든 경우에 할당은 오른쪽 및 왼쪽 피연산자의 값 계산 후 및 할당 표현식의 값 계산 전에 순서가 지정됩니다.

"가치 계산"은 무엇을 의미합니까?

1.9p12가 답을줍니다 :

휘발성 glvalue (3.10)로 지정된 객체에 액세스하거나, 객체를 수정하거나, 라이브러리 I / O 함수를 호출하거나, 이러한 작업 중 하나를 수행하는 함수를 호출하는 것은 부작용입니다. 이는 실행 환경의 상태 변화입니다. 표현식 (또는 하위 표현식) 평가에는 일반적으로 값 계산 (glvalue 평가를 위해 객체의 신원을 결정하고 이전에 평가를 위해 객체에 지정된 값을 가져 오는 작업 포함) 및 부작용의 개시가 포함됩니다.

코드에서 복합 할당 연산자를 사용하므로 5.17p7은이 연산자가 어떻게 작동하는지 알려줍니다.

E1 op= E2 형식의 표현식은 E1이 한 번만 평가 E1 = E1 op E2 except that E1 E1 = E1 op E2 except that 와 같습니다.

따라서 표현 E1 ( == i) 의 평가는 E1 ( == i) 지정된 객체의 신원을 결정하고 그 객체에 저장된 값을 가져 오기 위해 lvalue-to-rvalue 변환을 모두 포함합니다. 그러나 두 피연산자 E1E2 의 평가는 서로에 대해 순서가 E2 않습니다. 따라서 우리는 E2 ( == ++i + 1) 의 평가가 부작용 ( i 업데이트 E2 ( == ++i + 1) 시작하기 때문에 정의되지 않은 동작 을 얻습니다.

1.9p15 :

... 스칼라 객체의 부작용이 동일한 스칼라 객체의 다른 부작용 또는 동일한 스칼라 객체 의 값을 사용하는 값 ​​계산과 비교하여 순서가 지정되지 않은 경우 동작은 정의되지 않습니다.

귀하의 질문 / 의견에서 다음 진술은 귀하의 오해의 근원 인 것 같습니다 :

(2) 과제의 LHS도 lvalue이므로 가치 평가는 i 의 현재 값을 가져 오는 것과 관련이 없습니다.

값을 가져 오면 평가 값의 일부가 될 수 있습니다. 그러나 E + = F에서 유일한 prvalue는 F이므로 E의 값을 가져 오는 것이 (lvalue) 부 표현식 E의 평가의 일부가 아닙니다.

표현식이 lvalue 또는 rvalue 인 경우이 표현식을 평가하는 방법에 대해 아무 것도 알려주지 않습니다. 일부 연산자는 왼쪽 값을 피연산자로 필요로하고 다른 일부 연산자는 rvalues를 필요로합니다.

조항 5p8 :

glvalue 표현식이 해당 피연산자의 prvalue를 예상하는 연산자의 피연산자로 나타날 때마다 lvalue - to - rvalue (4.1), 배열 - 포인터 (4.2) 또는 함수 - 포인터 (4.3) 표준 변환은 다음과 같습니다. 표현식을 prvalue로 변환하기 위해 적용됩니다.

간단한 할당에서 LHS의 평가는 객체의 신원을 결정하기 만하면됩니다. 그러나 += 와 같은 복합 할당에서는 LHS가 수정 가능 값이어야합니다.이 경우 LHS의 평가는 객체의 식별 및 lvalue-to-rvalue 변환으로 구성됩니다. RHS 평가의 결과 (또한 prvalue)에 추가되는 것은이 변환 (prvalue)의 결과입니다.

"그러나 E + = F에서 유일한 prvalue는 F이므로 E의 값을 가져 오는 것이 (lvalue) 부 표현식 E의 평가의 일부가 아닙니다."

위에서 설명한 것처럼 사실이 아닙니다. 예제에서 F 는 prvalue 표현식이지만 F 는 lvalue 표현식 일 수도 있습니다. 이 경우 왼쪽 값과 오른쪽 값의 변환이 F 에도 적용됩니다. 위에서 인용 한 5.17p7은 복합 대입 연산자의 의미가 무엇인지 알려줍니다. 표준은 E += F거동E += F거동 과 동일하지만 E 는 한 번만 평가된다는 것을 나타냅니다. 여기서 E 의 평가는 좌변 값과 우변 값의 변환을 포함합니다. 왜냐하면 이진 연산자 + 는 피연산자가 오른쪽 값이어야하기 때문입니다.


표현식:

i += ++i + 1

정의되지 않은 동작을 호출합니다. 언어 변호사는 다음과 같은 결점 보고서로 돌아 가야합니다.

i = ++i + 1 ;

결함 보고서 637 인 C ++ 11에서 잘 정의되고 있습니다 . 시퀀싱 규칙과 예제는 동의하지 않습니다 .

1.9 [소개. 실행] 단락 16에서 정의되지 않은 동작의 예로서 다음 표현식이 여전히 나열됩니다.

i = ++i + 1;

그러나 새로운 시퀀싱 규칙은이 표현식을 잘 정의 된 것으로 보입니다.

보고서에 사용 된 논리는 다음과 같습니다.

  1. 할당 부작용은 LHS와 RHS (5.17 [expr.ass] 문단 1) 둘 다의 값 계산 후에 순차 화되어야한다.

  2. LHS (i)는 좌변 값이므로 값 계산은 i의 주소를 계산하는 것과 관련이 있습니다.

  3. RHS (++ i + 1)의 값을 계산하려면 먼저 lvalue 식 ++ i를 값 계산 한 다음 결과에 대해 왼쪽 값과 오른쪽 값의 변환을 수행해야합니다. 이는 증분 부작용이 덧셈 연산의 계산 전에 순서가 정해지고, 할당 부작용 전에 순서가 정해지는 것을 보장합니다. 즉,이 표현식에 대해 잘 정의 된 순서와 최종 값을 산출합니다.

그래서이 문제에서 우리의 문제는 RHS 를 변화시킵니다 :

++i + 1

에:

i + ++i + 1

초안 C ++ 11 표준 섹션 5.17 할당 및 복합 할당 연산자로 인해 :

E1 op = E2 형식의 표현식은 E1이 한 번만 평가된다는 점을 제외하고는 E1 = E1 op E2와 같습니다. [...]

이제 우리는 RHS 에있는 i 의 계산이 ++i 비례해서 순서가 정해지지 않았기 때문에 정의되지 않은 행동을합니다. 이것은 1.915 절에서 다음과 같이 말합니다 :

명시된 경우를 제외하고 개별 연산자의 피연산자와 개별 표현식의 하위 표현식에 대한 평가는 순서가 지정되지 않습니다. [주 : 프로그램 실행 중 두 번 이상 평가되는 표현식에서 서브 표현식의 순서가 지정되지 않은 순서로 정렬 된 평가는 다른 평가에서 일관되게 수행 될 필요가 없습니다. -end note] 연산자의 피연산자 값 계산은 연산자 결과 값 계산 전에 순서가 지정됩니다. 스. 라 오브젝트의 부작용이 동일한 스. 라 오브젝트의 다른 부작용 또는 동일한 스. 라 오브젝트의 값을 사용하는 값 ​​계산과 비교하여 순서가 지정되지 않은 경우, 동작은 정의되지 않습니다.

이것을 보여주는 실용적인 방법은 clang 을 사용하여 코드를 테스트하는 것입니다. 그러면 다음 경고가 생성됩니다 ( 실제보기 ).

warning: unsequenced modification and access to 'i' [-Wunsequenced]
i += ++i + 1 ;
  ~~ ^

이 코드의 경우 :

int main()
{
    int i = 0 ;

    i += ++i + 1 ;
}

이것은 -Wunsequenced에 대한 clang's 테스트 슈트에있는이 명시적인 테스트 예제에 의해 더욱 뒷받침된다.

 a += ++a; 

컴파일러 작가의 관점에서, 그들은 걱정하지 않는다 "i += ++i + 1"컴파일러가하는대로, 프로그래머가 올바른 결과를 얻을 수 있기 때문에,하지만 그들은 확실히 그들이 어떤 대가를 받아야. 그리고 아무도 그런 식으로 코드를 작성하지 않습니다. 어떤 컴파일러 작가가 관심 약이다

*p += ++(*q) + 1;

코드는 읽을 수 있어야 *p하고 *q, 증가 *q1, 및 증가 *p계산 일부 양만큼. 여기에 컴파일러 작가는 읽기 및 쓰기 작업의 순서에 대한 제한에 대한 관심. 다른 개체에 p와 q 포인트는 순서 차이는 없습니다 만, 경우에 분명히 경우 p == q그것은 차이를 만들 것입니다. 다시 말하지만, p다른 것 q코드를 작성하는 프로그래머가 미친 경우를 제외하고.

코드가 정의되지 않은함으로써, 언어 컴파일러가 미친 프로그래머를위한 배려없이 가장 빠른 코드를 생성 할 수 있습니다. 정의 된 코드를함으로써, 언어 심지어 느리게 실행 할 수 있습니다 미친 경우에 표준을 준수 코드를 생성하도록 컴파일러에 강제로. 두 컴파일러 작가와 제정신 프로그래머는 좋아하지 않는다.

동작은 C ++ (11)에 정의되어 그래서 경우에도, (A) 컴파일러는 C ++ 03 동작이 변경되지 않을 수 있기 때문에, 그것을 사용하는 것은 매우 위험 할 것, 그리고 (b)는 C에서 정의되지 않은 동작이있을 수 있습니다 위의 이유로 ++ (14).


i = ++i + 1 대한 설명

그 미묘한 설명은

(1) ++i 는 lvalue를 반환하지만 + 는 prvalues를 피연산자로 취하므로 lvalue에서 prvalue 로의 변환이 수행되어야합니다.

아마도 CWG 활성 문제 1642를 참조하십시오.

이것은 lvalue ( i 의 이전 값보다 하나가 아닌)의 현재 값을 얻는 것을 포함하므로 증분의 부작용 (즉, i 업데이트) 이후에 시퀀싱해야합니다.

여기서 시퀀스는 증가에 대해 정의됩니다 (간접적으로, += ,를 참조). ++ ( i 의 수정)의 부작용은 전체 표현식 ++i 의 값 계산 전에 순서가 지정됩니다. 후자는 ++i 의 값로드하는 것이 아니라 ++i 의 결과계산하는 것을 의미합니다.

(2) 과제의 LHS도 lvalue이므로 가치 평가는 i 의 현재 값을 가져 오는 것을 포함하지 않습니다. 이 값 계산은 RHS의 값 계산에 따라 결정되지 않지만 문제는 없습니다.

표준에서 제대로 정의되지 않았다고 생각하지만 동의합니다.

(3) 할당 자체의 값 계산은 i (다시)를 업데이트하는 것과 관련이있다.

i = expr 의 값 계산은 결과를 사용할 때만 필요합니다 int x = (i = expr); 예 : int x = (i = expr); 또는 (i = expr) = 42; . 값 계산 자체는 i 수정하지 않습니다.

i = expr 인해 발생하는 식 i = expr 에서 i 의 수정은 =부작용 이라고합니다. 이 부작용은 i = expr 의 값 계산 전에 순차 화되거나 i = expr 의 값 계산은 i = expr 에 대입의 부작용 후에 순차 화 됩니다.

일반적으로 표현식의 피연산자 값 계산은 해당 표현식의 부작용 전에 순서가 지정됩니다.

그 RHS의 값 계산 이후에, 따라서 i 대한 이전의 갱신 이후에 시퀀싱된다; 문제 없어.

할당 i = expr부작용 은 피연산자 i (A)의 값 계산과 할당의 i = expr 후에 순서화됩니다.

이 경우 expr+ 표현식 : expr1 + 1 입니다. 이 표현식의 값 계산은 피연산자 expr11 의 값 계산 후에 순서가 지정됩니다.

여기서 expr1++i 입니다. ++i 의 값 계산은 ++i ( ++i 의 수정) (B)의 부작용 후에 순서화됩니다.

그래서 i = ++i + 1 은 안전합니다 : (A)의 값 계산과 (B)의 같은 변수에 대한 부작용 사이에 일련순서가 있습니다.

(a) 표준은 expr += 1 관점에서 ++expr 을 정의하며 expr = expr + 1 로 정의되며 expr = expr + 1 은 한 번만 평가된다.

따라서이 expr = expr + 1 에 대해서 expr = expr + 1 대한 하나의 값 계산만을 갖는다. = 의 부작용은 expr = expr + 1 전체의 값 계산 전에 순서가 expr = expr + 1 지며 피연산자 expr (LHS) 및 expr + 1 (RHS)의 값 계산 후에 순서가 지정됩니다.

이것은 ++expr 대해 ++expr 의 값 계산 전에 부작용이 시퀀싱되었다는 나의 주장에 해당합니다.

i += ++i + 1

i += ++i + 1 의 값 계산은 정의되지 않은 동작을 포함합니까?

+= 의 LHS가 여전히 lvalue (그리고 그 RHS가 여전히 prvalue)이기 때문에, (1)과 (2)에 관한 한 동일한 추론이 적용됩니다. (3) += 연산자의 값 계산은 이제 i 의 현재 값을 가져와야하고 (표준이 명시 적으로 말하지 않더라도 분명히 그 다음에 이어져야합니다. 그렇지 않으면 그러한 연산자의 실행은 항상 정의되지 않은 동작을 호출) RHS의 추가를 수행하고 그 결과를 다시 i 저장합니다.

나는 여기에 문제가 있다고 생각한다. +++ ++i + 1 의 결과에 i += LHS에 i += 더하는 것은 i += 의 값을 알아야한다. - 값 계산 ( i 의 값을로드하는 것을 의미 할 수있다). 이 값 계산은 ++i 의해 수행 된 수정과 관련하여 순서가 지정되지 않습니다. 이것은 표준 i += expr -> i = i + expr 에 의해 위임 된 재 작성을 따르는 대체 설명에서 본질적으로 말하는 것입니다. 여기서 i + expr 내의 i + expr 의 값 계산은 expr 의 값 계산과 관련하여 순서가 지정되지 않습니다. 그것이 UB를 얻는 곳 입니다.

값 계산은 두 가지 결과를 가질 수 있습니다 : 객체의 "주소"또는 객체의 값. 식 i = 42 에서 lhs의 값 계산은 i 의 주소를 생성합니다. 즉, 컴파일러는 (추상 기계의 관찰 가능한 동작 규칙에 따라) rhs를 저장할 위치를 파악해야합니다. 식 i + 42 에서 i + 42 의 값 계산은 값을 생성합니다. 위의 단락에서 필자는 두 번째 종류를 언급 했으므로 [intro.execution] p15가 적용됩니다.

스. 라 오브젝트의 부작용이 동일한 스. 라 오브젝트의 다른 부작용 또는 동일한 스. 라 오브젝트의 값을 사용하는 값 ​​계산과 비교하여 순서가 지정되지 않은 경우, 동작은 정의되지 않습니다.

i += ++i + 1 대한 또 다른 접근법

+= 연산자의 값 계산은 이제 i 의 현재 값을 가져와야하고 [...] RHS의 추가를 수행해야합니다.

RHS는 ++i + 1 입니다. 이 표현 (값 계산)의 결과를 계산하는 것은 LHS로부터의 i 의 값 계산과 관련하여 순서가 정해지지 않는다. 따라서이 문장의 단어는 오해의 소지가 있습니다. 물론, 먼저 i 로드 한 다음 RHS의 결과를 추가해야합니다. 그러나 LHS의 가치를 얻으려면 RHS의 부작용과 가치 계산 사이에는 질서가 없습니다. 예를 들어, RHS에 의해 수정 된대로 이전 값 또는 새 값 중 하나를 LHS로 가져올 수 있습니다.

일반적으로 상점 및 "동시"로드는 데이터 경합이며 이로 인해 정의되지 않은 동작이 발생합니다.

부록 추가하기

가상의 ||| 연산자를 사용하여 순서가없는 평가를 지정하면 E op= F; (단순화를 위해 int 피연산자와 함께) { int& L=E ||| int R=F; L = L + R; } { int& L=E ||| int R=F; L = L + R; } { int& L=E ||| int R=F; L = L + R; } 하지만 예제에는 더 이상 UB가 없습니다.

Ei , F++i (우리는 + 1 필요 없습니다)라고합시다. 그런 다음, i = ++i

int* lhs_address;
int lhs_value;
int* rhs_address;
int rhs_value;

    (         lhs_address = &i)
||| (i = i+1, rhs_address = &i, rhs_value = *rhs_address);

*lhs_address = rhs_value;

반면에, i += ++i

    (         lhs_address = &i, lhs_value = *lhs_address)
||| (i = i+1, rhs_address = &i, rhs_value = *rhs_address);

int total_value = lhs_value + rhs_value;
*lhs_address = total_value;

이것은 시퀀싱 보장에 대한 나의 이해를 나타 내기위한 것입니다. 연산자는 모든 값 계산과 부작용을 RHS보다 먼저 계산합니다. 괄호는 순서 지정에 영향을주지 않습니다. 두 번째 경우, i += ++i 에서는 i => UB의 좌변과 우변으로 변환되지 않은 i 의 수정이 있습니다.

이 표준은 복합어 할당을 의미론에 대한 별도의 정의가 필요하지 않은 제 2 급 프리미티브로 취급하지 않습니다.

나는 그것이 중복이라고 말한다. E1 op = E2 에서 E1 = E1 op E2 E1 op = E2 로의 재 작성은 또한 필요한 표현식 유형과 값 범주 (rhs에 대해서는 5.17 / 1이 lhs에 대해 말함), 포인터 유형에 어떤 일이 일어나는지, 필요한 변환 등을 포함합니다. 슬픈 것은 5.17 / 1에있는 "존경과 관련하여"에 대한 문장이 그 등가물을 제외하고는 5.17 / 7에 없다는 것입니다.

어떤 식 으로든 저는 복합 과제와 단순 과제와 연산자에 대한 보증과 요구 사항을 비교하고 모순이 없는지 확인해야한다고 생각합니다.

우리가 5.17 / 7에있는 예외 목록에도 "..와 관련하여"그것을 둔다면 모순이 있다고 생각하지 않습니다.

Marc van Leeuwen의 답변에서 볼 수 있듯이이 문장은 다음과 같은 흥미로운 관찰을하게됩니다.

int i; // global
int& f() { return ++i; }
int main() {
    i  = i + f(); // (A)
    i +=     f(); // (B)
}

(A)는 두 가지 가능한 결과가있는 것으로 보인다. 왜냐하면 f 본문의 평가는 i + f() i 에서 i + f() 의 값 계산과 불확실하게 순서가 정해져 있기 때문이다.

반면에 (B)에서 f() 의 몸체 평가는 i 의 값 계산 전에 순서가 정해 지므로 += 는 단일 연산으로 간주되어야하므로 f() 반드시 += 할당.





undefined-behavior