bestsource

잘못된 메모리를 가리킬 때의 (*ptr) 동작의 크기가 정의되지 않습니까?

bestsource 2023. 9. 16. 09:32
반응형

잘못된 메모리를 가리킬 때의 (*ptr) 동작의 크기가 정의되지 않습니까?

null 포인터 또는 할당되지 않은 메모리에 대한 포인터를 다시 참조하면 정의되지 않은 동작이 발생한다는 것을 우리 모두는 알고 있습니다.

하지만 전달된 표현 안에서 사용될 때의 규칙은 무엇입니까?sizeof?

예를 들어,

int *ptr = 0;
int size = sizeof(*ptr);

이것도 정의가 안 된 건가요?

대부분의 경우, 당신은 그것을 발견할 것입니다.sizeof(*x)실제로 평가하지 않습니다.*x조금도.그리고, 정의되지 않은 동작을 호출하는 것은 포인터의 평가(비참조)이기 때문에 대부분 괜찮다는 것을 알게 될 것입니다.C11 표준은 다음과 같이 말합니다.6.5.3.4. The sizeof operator /2(이 모든 인용문에서 강조하는 바):

sizeofoperator는 피연산자의 크기(바이트 단위)를 산출하며, 식 또는 유형의 괄호가 붙은 이름일 수 있습니다.피연산자의 유형에 따라 크기가 결정됩니다.결과는 정수입니다.피연산자 유형이 가변 길이 배열 유형이면 피연산자를 평가하고, 그렇지 않으면 피연산자를 평가하지 않고 결과가 정수 상수입니다.

이것은 C99의 동일한 섹션과 동일한 문구입니다.C89는 그 시점에 당연히 VLA가 없었기 때문에 문구가 조금 달랐습니다.부터3.3.3.4. The sizeof operator:

sizeofoperator는 피연산자의 크기(바이트 단위)를 산출하며, 식 또는 유형의 괄호가 붙은 이름일 수 있습니다.크기는 피연산자의 유형에 따라 결정되며 피연산자 자체는 평가되지 않습니다.결과는 정수 상수입니다.

따라서 C에서는 모든 비 VLA에 대해 재참조가 이루어지지 않으며 문이 잘 정의되어 있습니다.유형이 다음과 같다면*x 이건 VLA야, 이건 사형 집행 단계로 간주됩니다.sizeof, 코드가 실행되는 동안 해결해야 하는 것 - 다른 것들은 컴파일 타임에 계산할 수 있습니다. 만약x그 자체가 VLA이며, 다른 경우와 동일하며, 사용 시 평가가 이루어지지 않습니다.*x에 대한 반론으로서sizeof().


C++는 표준의 다양한 반복에서 볼 수 있듯이 (예상했던 대로 다른 언어이기 때문에) 약간 다른 규칙을 가지고 있습니다:

첫번째,C++03 5.3.3. Sizeof /1:

sizeofoperator는 피연산자의 객체 표현에서 바이트 수를 산출합니다.피연산자가 평가되지 않은 식이거나 괄호로 묶은 형식-id입니다.

인,C++11 5.3.3. Sizeof /1, 약간 다른 문구가 있지만 효과는 같습니다.

sizeofoperator는 피연산자의 객체 표현에서 바이트 수를 산출합니다.피연산자는 평가되지 않은 피연산자인 식(제5항) 또는 괄호로 묶은 유형-id입니다.

C++11 5. Expressions /7(위의 조항 5)는 "평가되지 않은 피연산자"라는 용어를 아마도 제가 한동안 읽은 가장 쓸모없고 중복된 문구 중 하나로 정의하지만, ISO 사람들이 이 문구를 쓸 때 어떤 생각이 들었는지는 모르겠습니다.

일부 컨텍스트([해당 컨텍스트를 자세히 설명하는 섹션에 대한 일부 참조 - pax])에서는 평가되지 않은 피연산자가 나타납니다.평가되지 않은 피연산자는 평가되지 않습니다.

C++14/17은 C++11과 동일한 문구를 가지고 있지만 반드시 동일한 부분에 해당하는 것은 아닙니다.들어왔습니다.5.3.3. Sizeof /1그리고.5. Expressions /8 및 C++14우의 .8.3.3. Sizeof /1그리고.8. Expressions /8C++17의 경우.

따라서 C++에서 다음을 평가합니다.*x인에sizeof(*x) 를 들어, 완전한 유형을 제공하는 것과 같은 다른 모든 규칙을 준수한다면 이는 결코 발생하지 않으므로 잘 정의됩니다.그러나 결론은 재참조를 하지 않는다는 것인데, 이는 문제를 일으키지 않는다는 것을 의미합니다.

실제로 다음 프로그램에서 평가 불가를 확인할 수 있습니다.

#include <iostream>
#include <cmath>

int main() {
    int x = 42;
    std::cout << x << '\n';

    std::cout << sizeof(x = 6) << '\n';
    std::cout << sizeof(x++) << '\n';
    std::cout << sizeof(x = 15 * x * x + 7 * x - 12) << '\n';
    std::cout << sizeof(x += sqrt(4.0)) << '\n';

    std::cout << x << '\n';
}

최종 라인은 다음과 같이 매우 다른 것을 출력할 것이라고 생각할 수 있습니다.42(774, 내 대략적인 계산으로 볼 때)x꽤 많이 바뀌었습니다.그러나 실제로는 그렇지 않습니다. 왜냐하면 그것은 단지 의 표현의 종류이기 때문입니다.sizeof여기서 중요한 건, 유형은 어떤 유형이든 간에x입니다.

처음과 끝 이외의 행에서 포인터 크기가 다를 가능성을 제외하고 볼 수 있는 것은 다음과 같습니다.

42
4
4
4
4
42

아니요.sizeof는 연산자이며 실제 값(평가되지 않음)이 아닌 유형에 대해 작업합니다.

조작자임을 상기시키기 위해, 실용적인 경우 괄호를 생략하는 습관을 들이는 것을 추천합니다.

int* ptr = 0;
size_t size = sizeof *ptr;
size = sizeof (int);   /* brackets still required when naming a type */

C의 수 , 서 은 C 은 sizeof 구조체일 필요는 , C는일임이라시에서 C++는다o는서snsdc는,라시일cttn+e-yta임sizeof평가되지 않습니다.이와 같이, 정의되지 않은 행동이 스스로 나타날 가능성은 결코 없습니다.유사한 논리에 의해 [함수가 실제로 호출되지 않기 때문에 정의가 필요하지 않음], 즉 SFINAE 규칙에서 자주 사용되는 사실을 정의하지 않은 함수를 "호출"할 수도 있습니다.

sizeof그리고.decltype피연산자, 컴퓨팅 유형만 평가하지 않습니다.

sizeof(*ptr) .sizeof(int)이 경우에는

에 ( 배열의 ) 의 를 하지 에서 는 (C99 의 는 을 하는 에서 는 의 ) sizeof (*ptr) 않습니다 ptr 되지 되지 되지 되지 자는의만면다면다sefe 식의 유형만 하면 됩니다.*ptr적절한 사이즈를 얻기 위해서입니다.

언급URL : https://stackoverflow.com/questions/7721184/is-sizeofptr-undefined-behavior-when-pointing-to-invalid-memory

반응형