++ 연산자에 관한 C와 C ++의 차이점
나는 약간의 코드를 가지고 장난을 치며 "이유"를 이해하지 못하는 것을 보았다.
int i = 6;
int j;
int *ptr = &i;
int *ptr1 = &j
j = i++;
//now j == 6 and i == 7. Straightforward.
연산자를 등호 왼쪽에 놓으면 어떻게 될까요?
++ptr = ptr1;
다음과 같다
(ptr = ptr + 1) = ptr1;
이므로
ptr++ = ptr1;
다음과 같다
ptr = ptr + 1 = ptr1;
접미사는 컴파일 오류를 실행하고 그것을 얻습니다. 할당 연산자의 왼쪽에 상수 "ptr + 1"이 있습니다. 그럴 수 있지.
접두사 1은 C ++에서 컴파일되고 작동합니다. 예, 나는 그것이 지저분하고 할당되지 않은 메모리를 다루고 있음을 이해하지만 작동하고 컴파일됩니다. C에서는 컴파일되지 않고 접미사 "lvalue required as left operand of assignment"와 동일한 오류를 반환합니다. 이것은 작성 방법에 관계없이 두 개의 "="연산자 또는 "++ ptr"구문을 사용하여 확장됩니다.
C가 이러한 할당을 처리하는 방법과 C ++가 처리하는 방법의 차이점은 무엇입니까?
C와 C ++ 모두에서의 결과 x++
는 rvalue이므로 할당 할 수 없습니다.
C에서는, ++x
동등 x += 1
(, 모든 C 표준은 인용 WG14 N1570한다 §6.5.3.1 / P2가 C 표준). C ++에서 if is not a ++x
와 동일 합니다 (C ++ 표준 §5.3.2 [expr.pre.incr] / p1; 모든 C ++ 표준 인용은 WG21 N3936에 따름).x += 1
x
bool
C에서 할당 식의 결과는 rvalue (C 표준 §6.5.16 / p3)입니다.
할당 연산자는 왼쪽 피연산자로 지정된 개체에 값을 저장합니다. 할당 표현식은 할당 후 왼쪽 피연산자의 값을 갖지만 lvalue가 아닙니다.
lvalue가 아니기 때문에 할당 할 수 없습니다 : (C 표준 §6.5.16 / p2-이것이 제약이라는 점에 유의하세요)
할당 연산자는 왼쪽 피연산자로 수정 가능한 lvalue를 가져야합니다.
C ++에서 할당 표현식의 결과는 lvalue (C ++ 표준 §5.17 [expr.ass] / p1)입니다.
할당 연산자 (=)와 복합 할당 연산자는 모두 오른쪽에서 왼쪽으로 그룹화됩니다. 모두 왼쪽 피연산자로 수정 가능한 lvalue가 필요하고 왼쪽 피연산자를 참조하는 lvalue를 반환합니다.
따라서 ++ptr = ptr1;
C에서 진단 가능한 제약 조건 위반이 발생하지만 C ++의 진단 가능한 규칙을 위반하지는 않습니다.
그러나 pre-C ++ 11 은 두 개의 인접한 시퀀스 포인트 사이에서 두 번 ++ptr = ptr1;
수정되므로 정의되지 않은 동작이 ptr
있습니다.
C ++ 11에서는의 동작 ++ptr = ptr1
이 잘 정의됩니다. 다음과 같이 다시 작성하면 더 명확합니다.
(ptr += 1) = ptr1;
C ++ 11부터 C ++ 표준은이를 제공합니다 (§5.17 [expr.ass] / p1).
모든 경우에 할당은 오른쪽 및 왼쪽 피연산자의 값 계산 후 할당 식의 값 계산 전에 순서가 지정됩니다. 불확정 시퀀스 함수 호출과 관련하여 복합 할당 작업은 단일 평가입니다.
따라서에 의해 수행 된 할당 =
은 ptr += 1
및 의 값 계산 후에 순서가 지정됩니다 ptr1
. 에서 수행 한 할당 +=
은의 값 계산 전에 순서가 지정되며에서 ptr += 1
필요한 모든 값 계산 +=
은 반드시 해당 지정 전에 순서가 지정됩니다. 따라서 여기서 시퀀싱은 잘 정의되어 있으며 정의되지 않은 동작이 없습니다.
C에서 사전 및 사후 증가의 결과는 rvalue 이고 rvalue에 할당 할 수 없습니다 . lvalue 가 필요합니다 ( 또한 참조 : C 및 C ++의 lvalue 및 rvalue 이해 ). 우리는로 이동하여 볼 수 있습니다 초안 C11 표준 섹션 6.5.2.4
후위 증가 및 감소 연산자 (라고 강조 광산 향후 ) :
접미사 ++ 연산자 의 결과 는 피연산자 의 값 입니다. [...] 제약, 유형, 변환 및 포인터에 대한 연산의 효과에 대한 정보는 가산 연산자 및 복합 할당에 대한 설명을 참조하십시오. [...]
따라서 post-increment의 결과는 rvalue 와 동의어 인 값 이며 제약 조건과 결과에 대한 추가 이해를 위해 위의 단락이 가리키는 할당 연산자 섹션으로 이동하여 확인할 수 있습니다 .6.5.16
[...] 할당 표현식은 할당 후 왼쪽 피연산자의 값을 갖지만 lvalue가 아닙니다 . [...]
추가로 증가 후 결과가 lvalue 가 아님을 확인합니다 .
사전 6.5.3.1
증가의 경우 다음과 같은 접두사 증가 및 감소 연산자 섹션에서 볼 수 있습니다 .
[...] 제약, 유형, 부작용, 변환 및 포인터에 대한 연산의 효과에 대한 정보는 가산 연산자 및 복합 할당에 대한 설명을 참조하십시오.
또한 6.5.16
post-increment와 마찬가지로 다시 가리 키 므로 C의 pre-increment 결과도 lvalue 가 아닙니다 .
C ++에서 post-increment는 rvalue입니다 .보다 구체적으로 prvalue 는 5.2.6
Increment and decrement 섹션으로 이동하여 확인할 수 있습니다 .
[...] 결과는 prvalue입니다. 결과 유형은 피연산자 유형의 정규화되지 않은 cv 버전입니다 [...]
사전 증가와 관련하여 C와 C ++가 다릅니다. C에서는 결과가 rvalue 이고 C ++에서는 결과가 C ++에서는 작동하지만 C에서는 작동하지 않는 이유를 설명 하는 lvalue 입니다 ++ptr = ptr1;
.
C ++의 경우 다음 5.3.2
과 같은 증가 및 감소 섹션에서 다룹니다 .
[...] 결과는 업데이트 된 피연산자입니다. lvalue 이고 피연산자가 비트 필드이면 비트 필드입니다. [...]
다음 사항을 이해하려면 :
++ptr = ptr1;
C ++에서 잘 정의되어 있거나 그렇지 않은 경우 C ++ 11 이전과 C ++ 11에 대해 하나씩 두 가지 다른 접근 방식이 필요합니다.
Pre C++11 this expression invokes undefined behavior, since it is modifying the object more than once within the same sequence point. We can see this by going to a Pre C++11 draft standard section 5
Expressions which says:
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.57) Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [ Example:
i = v[i ++]; / / the behavior is undefined i = 7 , i++ , i ++; / / i becomes 9 i = ++ i + 1; / / the behavior is undefined i = i + 1; / / the value of i is incremented
—end example ]
We are incrementing ptr
and then subsequently assigning to it, which is two modifications and in this case the sequence point occurs at the end of the expression after the ;
.
For C+11, we should go to defect report 637: Sequencing rules and example disagree which was the defect report that resulted in:
i = ++i + 1;
becoming well defined behavior in C++11 whereas prior to C++11 this was undefined behavior. The explanation in this report is one of best I have even seen and reading it many times was enlightening and helped me understand many concepts in a new light.
The logic that lead to this expression becoming well defined behavior goes as follows:
The assignment side-effect is required to be sequenced after the value computations of both its LHS and RHS (5.17 [expr.ass] paragraph 1).
The LHS (i) is an lvalue, so its value computation involves computing the address of i.
In order to value-compute the RHS (++i + 1), it is necessary to first value-compute the lvalue expression ++i and then do an lvalue-to-rvalue conversion on the result. This guarantees that the incrementation side-effect is sequenced before the computation of the addition operation, which in turn is sequenced before the assignment side effect. In other words, it yields a well-defined order and final value for this expression.
The logic is somewhat similar for:
++ptr = ptr1;
The value computations of the LHS and RHS are sequenced before the assignment side-effect.
The RHS is an lvalue, so its value computation involves computing the address of ptr1.
In order to value-compute the LHS (++ptr), it is necessary to first value-compute the lvalue expression ++ptr and then do an lvalue-to-rvalue conversion on the result. This guarantees that the incrementation side-effect is sequenced before the assignment side effect. In other words, it yields a well-defined order and final value for this expression.
Note
The OP said:
Yes, I understand it's messy and you're dealing with unallocated memory, but it works and compiles.
Pointers to non-array objects are considered arrays of size one for additive operators, I am going to quote the draft C++ standard but C11 has almost the exact same text. From section 5.7
Additive operators:
For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
and further tells us pointing one past the end of an array is valid as long as you don't dereference the pointer:
[...]If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
so:
++ptr ;
is still a valid pointer.
참고URL : https://stackoverflow.com/questions/25654339/the-difference-between-c-and-c-regarding-the-operator
'developer tip' 카테고리의 다른 글
Ubuntu에서 JDK 10을 설치하는 방법은 무엇입니까? (0) | 2020.11.03 |
---|---|
템플릿에 Django 양식 필드의 값을 어떻게 표시합니까? (0) | 2020.11.03 |
컬렉션의 구문을 설명하십시오. (0) | 2020.11.02 |
react-router를 사용하여 다른 경로로 리디렉션하는 방법은 무엇입니까? (0) | 2020.11.02 |
GraphViz에 비해 너무 큰 무 방향 그래프 시각화? (0) | 2020.11.02 |