code

C ++ 11에 void 포인터 비교에 대한 이상한 절이 포함 된 이유는 무엇입니까?

codestyles 2020. 12. 13. 09:34
반응형

C ++ 11에 void 포인터 비교에 대한 이상한 절이 포함 된 이유는 무엇입니까?


다른 질문에 대한 참조를 확인하는 동안 C ++ 11에서 [expr.rel] ¶3에서 이상한 절을 발견했습니다.

포인터 void로 정의 된 결과와 비교 될 수있다 (포인터 변환 후)은 다음과 같다 : 두 포인터는 동일한 주소를 나타내고 또는 모두 널 포인터 값이 있다면, 결과가 true조작자인지 <=또는 >=false그렇지 그렇지 않으면 결과가 지정되지 않습니다.

이것은 두 개의 포인터가 캐스트되면 void *순서 관계가 더 이상 보장되지 않음 을 의미하는 것 같습니다 . 예를 들면 다음과 같습니다.

int foo[] = {1, 2, 3, 4, 5};
void *a = &foo[0];
void *b = &foo[1];
std::cout<<(a < b);

지정되지 않은 것 같습니다.

흥미롭게도이 절은 C ++ 03에는없고 C ++ 14에서는 사라졌습니다. 따라서 위의 예를 들어 C ++ 14 단어를 적용하면 ¶3.1

  • 두 포인터가 동일한 배열의 다른 요소 또는 하위 객체를 가리키는 경우 더 높은 첨자를 가진 요소에 대한 포인터가 더 크게 비교됩니다.

로 적용 할 ab그들이에 주조 된 경우에도, 점 같은 배열의 요소 void *. ¶3.1의 표현은 C ++ 11에서도 거의 동일하지만 void *절에 의해 무시 된 것처럼 보였습니다 .

내 이해가 옳은가? C ++ 11에서 추가되고 즉시 제거 된 이상한 절의 요점은 무엇입니까? 아니면 아직 거기에 있지만 표준의 다른 부분으로 옮겨 졌거나 암시 되었습니까?


TL; DR :

  • C ++ 98 / 03에서는이 절이 존재하지 않았고 표준은 void포인터 대한 관계 연산자를 지정하지 않았습니다 (핵심 문제 879,이 게시물 끝 참조).
  • void포인터 비교에 대한 이상한 절이 이를 해결하기 위해 C ++ 11에 추가되었지만 이로 인해 다른 두 가지 핵심 문제 583 및 1512가 발생했습니다 (아래 참조).
  • 이러한 문제를 해결하려면 절을 제거하고 C ++ 14 표준에있는 문구로 교체해야하므로 "정상" void *비교가 가능합니다.

핵심 문제 583 : 널 포인터 상수에 대한 관계형 포인터 비교

  1. 널 포인터 상수에 대한 관계형 포인터 비교 섹션 : 8.9 [expr.rel]

C에서는 형식이 잘못되었습니다 (C99 6.5.8 참조).

void f(char* s) {
    if (s < 0) { }
} ...but in C++, it's not. Why? Who would ever need to write (s > 0) when they could just as well write (s != 0)?

이것은 ARM (그리고 아마도 그 이전) 이후의 언어로되어 있습니다. 피연산자 중 하나가 포인터 유형일 때마다 두 피연산자 모두에서 포인터 변환 (7.11 [conv.ptr])을 수행해야하기 때문입니다. 따라서 "null-ptr-to-real-pointer-type"변환이 다른 포인터 변환과 함께 타는 것처럼 보입니다.

제안 된 결의안 (2013 년 4 월) :

이 문제는 문제 1512 의 해결로 해결되었습니다 .

핵심 이슈 1512 : 포인터 비교 vs 자격 변환

  1. 포인터 비교 vs 자격 변환 섹션 : 8.9 [expr.rel]

8.9 [expr.rel] 단락 2에 따르면 포인터 비교를 설명합니다.

포인터 변환 (7.11 [conv.ptr]) 및 제한 변환 (7.5 [conv.qual])은 포인터 피연산자 (또는 포인터 피연산자 및 널 포인터 상수 또는 두 개의 널 포인터 상수에 대해 수행됩니다. 정수가 아님)을 복합 포인터 유형으로 가져옵니다. 이로 인해 다음 예제가 잘못된 것으로 보입니다.

 bool foo(int** x, const int** y) {
 return x < y;  // valid ?   } because int** cannot be converted to const int**, according to the rules of 7.5 [conv.qual] paragraph 4.

이것은 포인터 비교에 너무 엄격 해 보이며 현재 구현에서는 예제를 받아들입니다.

제안 된 결의안 (2012 년 11 월) :


위의 문제 해결 에서 발췌 한 관련 내용은 다음 논문에서 찾을 수 있습니다. 포인터 비교 대 자격 변환 (개정판 3) .

다음은 핵심 문제 583 도 해결합니다 .

5.9 expr.rel 단락 1에서 5로 변경 :

이 섹션에서는 다음 문 ( C ++ 11odd 절 )이 삭제 되었습니다 .

포인터 void로 정의 된 결과와 비교 될 수있다 (포인터 변환 후)은 다음과 같다 : 두 포인터는 동일한 주소를 나타내고 또는 모두 널 포인터 값이 있다면, 결과가 true조작자인지 <=또는 >=false그렇지 그렇지 않으면 결과가 지정되지 않습니다.

그리고 다음 문장이 추가되었습니다 .

  • 두 포인터가 동일한 배열의 다른 요소 또는 하위 객체를 가리키는 경우 더 높은 첨자를 가진 요소에 대한 포인터가 더 크게 비교됩니다.
  • 하나의 포인터가 배열의 요소 또는 하위 객체를 가리키고 다른 포인터가 배열의 마지막 요소를 지나서 가리키면 후자의 포인터가 더 크게 비교됩니다.

따라서 C ++ 14 (n4140) 섹션 [expr.rel] / 3 의 최종 작업 초안 에서 위의 진술은 해결 시점에 언급 된대로 발견됩니다.


이 이상한 절이 추가 된 이유를 파헤 치면 훨씬 더 이른 문제인 879 : Missing built-in comparison operator for pointer types . 이 문제에 대한 제안 된 해결책 (2009 년 7 월)에 따라 2009 년 10 월 WP에 투표 된이 조항이 추가되었습니다.

이것이 C ++ 11 표준에 포함 된 방법입니다.

참고URL : https://stackoverflow.com/questions/54362209/why-does-c11-contain-an-odd-clause-about-comparing-void-pointers

반응형