ProgramingTip

배열의 최대 크기가 "너무 큰"이유는 무엇입니까?

bestdevel 2021. 1. 7. 21:26
반응형

배열의 최대 크기가 "너무 큰"이유는 무엇입니까?


나는 같은 인상을 해요이 대답 , size_t주어진 시스템의 가장 큰 가능한 유형을 보유 할 충분한 표준에 의해 보장된다.

그러나이 코드는 gcc / Mingw에서 검증되지 않습니다.

#include <stdint.h>
#include <stddef.h>

typedef uint8_t array_t [SIZE_MAX];

오류 : 배열 'array_t'의 크기가 너무 섭섭니다.

여기 표준에서 뭔가 오해하고 있습니까? 주어진 size_t구현을 위해 너무 클 수? 아니면 Mingw의 또 다른 버그입니까?


편집 : 추가 연구에 따르면

typedef uint8_t array_t [SIZE_MAX/2];   // does compile
typedef uint8_t array_t [SIZE_MAX/2+1]; // does not compile

다음과 같은 일이 발생합니다.

#include <limits.h>

typedef uint8_t array_t [LLONG_MAX];           // does compile
typedef uint8_t array_t [LLONG_MAX+(size_t)1]; // does not compile

그래서 저는 이제 이것이 Mingw의 버그라고 믿고 있습니다. 부호있는 정수 유형을 기반으로 최대 허용 크기를 설정하는 것은 의미가 있기 때문입니다.


제한 SIZE_MAX / 2는 ptrdiff_t 및 size_t 유형이 너비를 갖도록 선택하는 구현의 size_t 및 ptrdiff_t 정의에서 비롯됩니다.

C 표준 은 size_t 유형이 서명되지 않고 ptrdiff_t 유형이 서명 1요구 합니다.

두 포인터 값 차이의 결과는 항상 2 가 ptrdiff_t 유형을 갖습니다. 즉, 구현시 개체의 크기를 PTRDIFF_MAX로 제한해야합니다. 일치하지 않는 두 포인터의 유효한 차이를 ptrdiff_t 형식으로 표현할 수 없어 정의되지 않은 동작이 발생합니다.

따라서 SIZE_MAX / 2 값은 PTRDIFF_MAX 값과 가변적입니다. 구현에서 최대 크기를 SIZE_MAX로 선택하면 ptrdiff_t 유형의 너비를 늘려야합니다. 그러나 클래스의 최대 크기를 SIZE_MAX / 2로 제한하는 것이 훨씬 더 있습니다. 그러면 ptrdiff_t 유형이 size_t 유형보다 크거나 같은 양의 범위를 갖도록하는 것이 부담 스럽습니다.

Standard는 주제 에 대한 3 개의 댓글 4가 제공 됩니다.


(ISO / IEC 9899 : 201x에서 인용)

1 (7.19 공통 정의 2)
유형은 두 포인터를 뺀 결과의 부호있는 정수 유형 인
ptrdiff_t
입니다. sizeof 연산자 결과의 부호없는 정수 유형 인
size_t
;

2 (6.5.6 덧셈 연산자 9)
두 포인터를 빼면 둘 다 배열 배열의 요소를 가리켜 야하거나 배열의 마지막 요소를 지나는 하나를 가리켜 야합니다. 결과는 두 배열 요소의 첨자의 차이입니다. 결과의 크기는 구현에 따라 정의 된 해당 유형 (부호있는 정수 유형)은 헤더에 정의 된 ptrdiff_t입니다. 결과가 해당 유형의 객체에서 표현할 수없는 경우 동작은 정의되지 않습니다.

3 (K.3.4 정수 유형 3)
매우 큰 개체 크기는 개체 크기가 잘못 계산되는 것은 신호입니다. 예를 들어 음수는 size_t와 같은 부호없는 유형으로 변환 될 때 매우 큰 양수로 나타납니다. 또한 일부 구현은 size_t 유형으로 표현할 수있는 최대 값만큼 큰 수업을 지원하지 않습니다.

4 (K.3.4 정수 유형 4)
그래야만 프로그래밍 오류를 감지하기 위해 클래스 크기 범위를 제한하는 것이 유익합니다. 주소 공간이 큰 머신을 대상으로하는 구현의 경우, RSIZE_MAX는 지원되는 가장 큰 개체의 크기 또는 (SIZE_MAX >> 1)보다 작은 것이 정의하는 것이 좋습니다.이 제한이 일부 합법적 인 크기보다 작지만 매우 물건입니다. 컴퓨터를 대상으로하는 작은 주소 공간을 가진 구현에서는 RSIZE_MAX를 SIZE_MAX로 정의 할 수 있습니다. 즉, 알림이 제공되는 개체 크기가 없음을 의미합니다.


범위의 범위 size_t는 구현에서 지원하는 가장 큰 개체의 크기를 저장하기에 충분합니다. 그 반대는 사실이 아닙니다. 크기가의 전체 범위를 채우는 개체를 만들 수 있다는 보장은 없습니다 size_t.

이러한 상황에서 질문은 무엇 SIZE_MAX을 의미합니까? 지원되는 가장 큰 개체 크기는 무엇입니까? 또는 size_t? 대답은 후자 SIZE_MAX입니다 (size_t) -1. . SIZE_MAX개체를 만들 수 있다는 보장은 없습니다 .

그 뒤에있는 이유는 size_t구현시를 제공해야하기 때문입니다 ptrdiff_t. 이는 동일한 배열 객체를 가리키는 두 포인터 간의 차이를 저장하도록 의도되었지만 보장되지는 않습니다. 유형 ptrdiff_t이 서명되었으므로 구현에는 다음 선택 사항이 있습니다.

  1. 크기의 어레이 객체를 허용 SIZE_MAX하고하게 ptrdiff_t 넓어 보다 size_t. 적어도 1 비트 더 넓어야합니다. 이러한 ptrdiff_t크기의 배열을 가리키는 두 개의 포인터의 차이 대응할 수 SIZE_MAX이하인.

  2. 크기의 어레이 오브젝트 허용 SIZE_MAX및 사용 ptrdiff_t동일한 폭 등을 size_t. 포인터가 요소 보다 멀리 떨어져 있으면 포인터 빼기가 오버플로 되어 정의되지 않은 동작을 유발할 수 있다는 사실을 받아들 SIZE_MAX / 2입니다. 언어 사양은이 접근 방식을 금지하지 않습니다.

  3. 사용 ptrdiff_t과 같은 폭 size_t제한 에 의한 최대 배열 객체의 크기를 SIZE_MAX / 2. 이러한 ptrdiff_t크기의 배열을 가리키는 두 개의 포인터의 차이 대응할 수 SIZE_MAX / 2이하인.

세 번째 접근 방식을 따르기로 결정한 구현을 단순히 다루고 있습니다.


구현 별 동작과 매우 유사합니다.

저는 여기서 Mac OS를 실행하고 있으며 gcc 6.3.0에서 정의를 컴파일 할 수있는 가장 큰 크기는 다음과 같습니다 SIZE_MAX/2. SIZE_MAX/2 + 1그것을 더 이상 컴파일되지 않습니다.

반면에 마녀 clang 4.0.0이 가장 큰 것은 SIZE_MAX/8이며 SIZE_MAX/8 + 1중단됩니다.


처음부터 추론하는 것만 size_t으로 어떤 물체의 크기도 담을 수있는 유형입니다. 객체의 크기는 주소 버스의 너비에 의해 제한됩니다 (예를 들어 32 비트 및 64 비트 코드를 처리 할 수있는 멀티플렉싱 및 시스템을 무시하고 "코드 너비"라고 함). MAX_INT가장 큰 정수 값인 Anologous SIZE_MAX는의 가장 큰 값입니다 size_t. 따라서 크기의 개체 SIZE_MAX는 모두 주소 지정이 가능한 메모리입니다. 구현시 오류로 플래그를 지정하는 것이 합리적이지만 스택 또는 전역 메모리에있는 실제 개체가 할당 된 경우에만 오류라는 데 동의합니다. ( malloc어쨌든 그 금액 대한 호출 은 실패합니다)

참조 URL : https://stackoverflow.com/questions/42574890/why-is-the-maximum-size-of-an-array-too-large

반응형