C와 C ++에서 + =의 결과는 무엇입니까?


93

다음 코드가 있습니다.

#include <stdio.h>
int main(int argc, char **argv) {
    int i = 0;
    (i+=10)+=10;
    printf("i = %d\n", i);
    return 0;
}

gcc를 사용하여 C 소스로 컴파일하려고하면 오류가 발생합니다.

error: lvalue required as left operand of assignment

그러나 g ++를 사용하여 C ++ 소스로 컴파일하면 오류가 발생하지 않고 실행 파일을 실행할 때 :

i = 20

왜 다른 행동입니까?


85
다른 언어, 다른 구문 규칙?. 개인적으로 코드 검토에서 해당 코드를 거부합니다.
Max

7
이 imo와 같은 코드를 피하십시오 ... 모든 사람에게 불분명합니다.
allaire

1
의심 할 여지없이 코드는 깨끗하지 않으며 "실제"개발에서는 피해야합니다. 그럼에도 불구하고 나는 같은 행동을 관찰하고 그 이유를 알고 싶습니다.
ulidtko

9
이것은 실제 소프트웨어에서 발췌 한 코드가 아닙니다. 이것은 내가 우연히 우연히 만난 꼬임입니다.
Svetlin Mladenov

3
@JohnDibling 나는 upvote가 특히 (i + = 10) + = 10이라고 생각합니다. 나는 합법적 인 코드가 어떤 언어인지 모르겠고 그가 C ++이 실제로 그것을 컴파일한다고 말하는 사실이 저를 흥미롭게합니다.
Tony318

답변:


133

복합 할당 연산자의 의미는 C와 C ++에서 다릅니다.

C99 표준, 6.5.16, 파트 3 :

할당 연산자는 왼쪽 피연산자로 지정된 개체에 값을 저장합니다. 할당 표현식은 할당 후 왼쪽 피연산자의 값을 갖지만 lvalue가 아닙니다.

C ++ 5.17.1에서 :

할당 연산자 (=)와 복합 할당 연산자는 모두 오른쪽에서 왼쪽으로 그룹화됩니다. 모두 왼쪽 피연산자로 수정 가능한 lvalue가 필요하고 할당이 발생한 후 왼쪽 피연산자의 유형과 값과 함께 lvalue를 반환합니다.

편집 :(i+=10)+=10 C ++ 의 동작은 C ++ 98에서는 정의되지 않았지만 C ++ 11에서는 잘 정의되어 있습니다. 표준의 관련 부분에 대해서는 NPE 의 질문에 대한 이 답변 을 참조하십시오 .


옳은. 하나는 결과 값을 반환하고 하나는 변수 (주소)를 반환합니다.
texasbruce

7
중요 : (i+=10)+=10C ++에서 정의되지 않은 동작입니다. @aix 답변을 참조하십시오.
David Rodríguez-dribeas

@ DavidRodríguez-dribeas 당신은 불특정 , 정의 되지 않은 것을 의미 했습니다.
dasblinkenlight

4
@dasblinkenlight : 아니요, 정의되지 않음을 의미했습니다 . C ++ 03 및 이전 버전에서 식의 lvalue 결과를 수정하면 중간 시퀀스 지점이 없기 때문에 모든 컴파일러에서 예기치 않게 작동 합니다. 이 인 경우에 지정되지 않은 , 그것은 것입니다 다른 컴파일러에 예상 할 수 있지만, 다르게 행동 .
Justin ᚅᚔᚈᚄᚒᚔ

2
int f(int &y); f(x += 10);수정 된 변수에 대한 참조를 함수에 전달하는 것과 같은 설정에서 유용했을 것 입니다.
Phil Miller

51

유효하지 않은 C 코드 인 것 외에도

(i+=10)+=10;

C 및 C ++ 03 모두에서 정의되지 않은 동작이 발생합니다. i시퀀스 포인트 사이에서 두 번 합니다.

C ++로 컴파일 할 수있는 이유는 다음과 같습니다.

[C ++ N3242 5.17.1] 할당 연산자 (=)와 복합 할당 연산자는 모두 오른쪽에서 왼쪽으로 그룹화됩니다. 모두 왼쪽 피연산자로 수정 가능한 lvalue가 필요하고 왼쪽 피연산자를 참조하는 lvalue를 반환합니다.

같은 단락이 계속해서

모든 경우에 할당은 오른쪽 및 왼쪽 피연산자의 값 계산 후 할당 식의 값 계산 전에 순서가 지정됩니다.

이는 C ++ 11에서 표현식에 더 이상 정의되지 않은 동작이 없음을 나타냅니다.


3
음, 시퀀스 포인트 때문에 확실히 UB입니다. 또한 C에서 유효하지 않은 코드 (C ++ 아님)이지만 시퀀스 포인트와 관련이 없으며 컴파일러에 의해 포착되어야합니다.
Konrad Rudolph

2
@KonradRudolph : 아니요, 컴파일러는 잘못된 형식의 코드와 달리 정의되지 않은 동작을 포착 할 의무가 없습니다. "컴파일러에 의해 잡혀야한다"부분은 우리가 동의하지 않는 부분입니다.

2
시퀀스 포인트는 C ++ 11에 존재하지 않으므로 UB에 대한 실제 이유 i는 시퀀스되지 않은 두 가지 수정 사항이 있기 때문 입니다.
Mankarse

4
이것이 정의되지 않은 동작이라는 것은 거짓입니다. 할당 식의 값 계산 전에 할당이 시퀀스가 ​​아닌 i = j+=1경우 불확실한 값이 발생합니다. 같은 단락에서 "모든 경우에 할당은 오른쪽 및 왼쪽 피연산자의 값 계산 후, 할당 식의 값 계산 전에"순서가 지정됩니다. 따라서 (i+=10)+=10잘 정의되어 있습니다 i += 10; i += 10;. 반면 (i+=10)+=(i+=10)에 UB입니다.
bames53

2
댓글 작성자간에 의견 차이가 있음을 확인한 후 별도의 질문으로 게시했습니다. stackoverflow.com/questions/10655290/…
NPE
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.