[c] c = ++ (a + b)에서 컴파일 오류가 발생하는 이유는 무엇입니까?

조사한 후 증분 연산자에는 피연산자가 수정 가능한 데이터 개체가 필요하다는 것을 읽었습니다. https://en.wikipedia.org/wiki/Increment_and_decrement_operators .

이것으로부터 나는 (a+b)임시 정수이므로 수정할 수 없기 때문에 컴파일 오류가 발생한다고 생각합니다 .

이 이해가 맞습니까? 문제를 조사하는 것은 이번이 처음 이니 찾아보아야 할 것이 있다면 조언 해주십시오.



답변

그것은 단지 규칙 일 뿐이며 (1) C 컴파일러를 더 쉽게 작성하고 (2) 아무도 C 표준위원회가이를 완화하도록 설득하지 않았습니다.

비공식적으로 말하면 과 같은 할당 표현식의 왼쪽에 can이 나타날 때만 쓸 ++foofoo있습니다 foo = bar. 당신이 쓸 수 없기 때문에 당신도 쓸 a + b = bar수 없습니다 ++(a + b).

작동 할 수 a + b있는 임시를 산출 할 수 없는 실제 이유 는 없으며 ++그 결과는 표현식의 값입니다 ++(a + b).


답변

섹션 6.5.3.1의 C11 표준 상태

접두사 증가 또는 감소 연산자의 피연산자는 원자, 규정 또는 규정되지 않은 실수 또는 포인터 유형을 가져야하며 수정 가능한 lvalue 여야합니다.

“수정 가능한 lvalue”는 섹션 6.3.2.1 하위 섹션 1에 설명되어 있습니다.

lvalue는 객체를 잠재적으로 지정하는 표현식 (void 이외의 객체 유형)입니다. lvalue가 평가 될 때 객체를 지정하지 않으면 동작이 정의되지 않습니다. 객체가 특정 유형을 갖는다 고 할 때 유형은 객체를 지정하는 데 사용되는 lvalue에 의해 지정됩니다. 수정 가능한 lvalue는 배열 유형이없고 불완전한 유형이없고 const 규정 된 유형이 없으며 구조 또는 공용체 인 경우 멤버가없는 lvalue입니다 (재귀 적으로 모든 멤버 포함). 또는 포함 된 모든 집계 또는 공용체의 요소)를 const 한정 형식으로 지정합니다.

그래서 (a+b)수정 가능한 좌변 아니므로 접두사 증가 연산자에 적합하지 않습니다.


답변

당신이 올바른지. 은 ++원래 변수에 새로운 값을 할당하려고합니다. 따라서 ++a의 값을 가져 와서 a추가 1한 다음에 다시 할당합니다 a. 말했듯이, (a + b)는 임시 값이고 할당 된 메모리 주소가있는 변수가 아니기 때문에 할당을 수행 할 수 없습니다.


답변

대부분 자신의 질문에 대답 한 것 같습니다. C.Gibbons가 언급했듯이 구문을 약간 변경하고 “임시 변수”를 “rvalue”로 바꿀 수 있습니다.

변수, 인수, 임시 변수 등의 용어는 C의 메모리 모델에 대해 배울수록 더 명확해질 것입니다 (멋진 개요처럼 보입니다 : https://www.geeksforgeeks.org/memory-layout-of-c-program/). ).

“rvalue”라는 용어는 처음 시작할 때 불투명 해 보일 수 있으므로 다음 내용이 이에 대한 직관을 개발하는 데 도움이되기를 바랍니다.

Lvalue / rvalue는 등호 (할당 연산자)의 다른 측면에 대해 설명합니다. lvalue = 왼쪽 ( “일”이 아닌 소문자 L) rvalue = 오른쪽

C가 메모리 (및 레지스터)를 사용하는 방법에 대해 조금 배우면 구별이 중요한 이유를 확인하는 데 도움이됩니다. 에서 폭 넓은 브러시 스트로크 , 컴파일러는 표현합니다 (를 rvalue)의 결과를 계산하는 기계 언어 명령어의 목록을 만든 다음 박았 그 결과 어딘가합니다 (좌변)을. 다음 코드 조각을 처리하는 컴파일러를 상상해보십시오.

x = y * 3

어셈블리 의사 코드에서는 다음과 같은 장난감 예제와 같이 보일 수 있습니다 .

load register A with the value at memory address y
load register B with a value of 3
multiply register A and B, saving the result in A
write register A to memory address x

++ 연산자 (및 그에 상응하는-)는 수정할 “어딘가”, 본질적으로 lvalue로 작동 할 수있는 모든 것이 필요합니다.

C 메모리 모델을 이해하면 인수가 함수에 전달되는 방법과 (결국) malloc () 함수와 같은 동적 메모리 할당을 사용하는 방법에 대해 더 나은 아이디어를 얻을 수 있기 때문에 도움이 될 것입니다. 비슷한 이유로 컴파일러가 수행하는 작업에 대한 더 나은 아이디어를 얻기 위해 어떤 시점에서 간단한 어셈블리 프로그래밍을 공부할 수 있습니다. 또한 gcc 를 사용하는 경우 -S 옵션 “적절한 컴파일 단계 후에 중지하십시오. 어셈블하지 마십시오.” 흥미로울 수 있습니다 ( 작은 코드 조각 에서 시도하는 것이 좋습니다 ).

제쳐두고 : ++ 명령어 는 1969 년부터 사용 되어 왔습니다 (C의 전임자 B에서 시작되었지만).

(Ken Thompson의) 관찰은 ++ x의 번역이 x = x + 1의 번역보다 작다는 것이 었습니다. “

위키피디아 참조를 따라 가면 편리하게 여기에 링크 된 C 언어의 역사에 대한 Dennis Ritchie ( “K & R C”의 “R”)의 흥미로운 글을 볼 수 있습니다. http://www.bell-labs.com/ usr / dmr / www / chist.html 여기서 “++”를 검색 할 수 있습니다.


답변

그 이유는 표준에서 피연산자가 lvalue 여야하기 때문입니다. 표현식 (a+b)이 lvalue가 아니므로 증분 연산자를 적용 할 수 없습니다.

이제, 하나는 말할 수있다 “정말로 이유지만, 실제로는 더 * 진짜 *의보다 다른 이유가 없다는 것을 확인” 하지만 불행하게도 운전자가 사실로 작동하는 방법의 특정 문구 않는 경우가 해당이 필요가.

표현식 ++ E는 (E + = 1)과 같습니다.

물론, 당신은 쓸 수없는 E += 1경우 E좌변이 아니다. “E를 하나씩 증가시킨다” 고 말할 수 있었기 때문에 부끄러운 일입니다. 이 경우, 비 lvalue에 연산자를 적용하는 것은 (원칙적으로) 컴파일러를 약간 더 복잡하게 만드는 대신 완벽하게 가능합니다.

이제 정의는 사소하게 바꿀 수 있지만 (원래 C도 아니지만 B의 가보라고 생각합니다) 그렇게하면 근본적으로 언어가 이전 버전과 더 이상 호환되지 않는 언어로 변경됩니다. 가능한 이점은 다소 적지 만 가능한 의미는 엄청 나기 때문에 결코 일어나지 않았으며 아마도 결코 일어나지 않을 것입니다.

C 외에 C ++를 고려한다면 (질문은 C로 태그되었지만 연산자 오버로드에 대한 논의가있었습니다) 이야기는 훨씬 더 복잡해집니다. C에서는 이것이 사실 일 수 있다고 상상하기 어렵지만 C ++에서는 그 결과가 (a+b)전혀 증가 할 수없는 것이거나 증가하는 것이 매우 상당한 부작용을 가질 수 있습니다 (단지 1을 추가하는 것이 아니라). 컴파일러는 이에 대처할 수 있어야하며 문제 발생시 문제를 진단 할 수 있어야합니다. lvalue에서는 여전히 확인하기가 쉽지 않습니다. 괄호 안의 어떤 종류의 우연한 표현도 당신이 가난한 것을 던지는 것은 아닙니다.
이것이 불가능한 진짜 이유 가 아닙니다. 그러나이를 구현 한 사람들이 소수의 사람들에게 거의 이익을 약속하지 않는 그러한 기능을 추가하는 것이 정확히 황홀하지 않은 이유를 설명 할 수 있습니다.


답변

(a + b)는 증가 할 수없는 rvalue로 평가됩니다.


답변

++는 원래 변수에 값을 제공하려고 시도하며 (a + b)는 임시 값이므로 연산을 수행 할 수 없습니다. 그리고 그것들은 기본적으로 프로그래밍을 쉽게하기위한 C 프로그래밍 규칙의 규칙입니다. 그게 다야.