programing

C에서 어레이 인덱스의 올바른 유형은 무엇입니까?

itsource 2022. 8. 1. 22:14
반응형

C에서 어레이 인덱스의 올바른 유형은 무엇입니까?

C99에서 사용할 어레이 인덱스의 유형을 선택하십시오.LP32, ILP32, ILP64, LP64, LLP64 등에서 동작해야 합니다.C89 타입일 필요는 없습니다.

5명의 후보를 찾았습니다.

  • size_t
  • ptrdiff_t
  • intptr_tuintptr_t
  • int_fast*_tuint_fast*_t
  • int_least*_tuint_least*_t

문제를 더 잘 설명하기 위한 간단한 코드가 있습니다.요?i ★★★★★★★★★★★★★★★★★」j이 두 가지 특정한 루프에서요.이유가 있다면 두 가지 종류도 상관없습니다.

for (i=0; i<imax; i++) {
        do_something(a[i]);
}
/* jmin can be less than 0 */
for (j=jmin; j<jmax; j++) {
        do_something(a[j]);
}

추신: 질문의 첫 번째 버전에서 저는 부정적인 지수에 대해 잊고 있었습니다.

P.P.S. C99 컴파일러는 쓰지 않겠습니다.하지만 컴파일러 프로그래머의 어떤 답변도 제게는 매우 소중할 것입니다.

유사한 질문:

거의 ★★★★★★★★★★★★★★★★★★★를 사용하고 있다.size_t★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★물론 서명된 오프셋을 필요로 하는 특수한 경우도 있지만 일반적으로 서명된 유형을 사용하는 데는 많은 문제가 있습니다.

가장 큰 위험은 발신자가 서명되지 않은 것으로 취급하는 거대한 크기/오프셋을 전달받았을 경우(또는 잘못 신뢰된 파일에서 읽었을 경우) 음수로 해석하여 범위를 벗어난 것을 발견하지 못할 수 있다는 것입니다.를 들면, 「 」입니다.if (offset<size) array[offset]=foo; else error();써서는 안 될 곳에 쓸 거야

또 다른 문제는 서명된 정수 오버플로에서 정의되지 않은 동작이 발생할 수 있다는 것입니다.서명되지 않은 산수를 사용하든, 서명되지 않은 산수를 사용하든 간에, 주의하고 확인해야 할 오버플로 문제가 있지만, 개인적으로 서명되지 않은 동작은 훨씬 다루기 쉽습니다.

부호 없는 산술(일반적으로)을 사용하는 또 다른 이유 - 때때로 인덱스를 비트 배열의 오프셋으로 사용하고 있으며 %8과 /8 또는 %32와 /32를 사용하고 싶습니다.서명이 있는 타입의 경우는, 실제의 분할 조작이 됩니다.부호 없는 경우 예상되는 비트 및/시프트 연산을 생성할 수 있습니다.

에 당신은 내생엔 i i i i i i i i i i i i i i i i i i i i i i i i i i 。ptrdiff_t과 같은

  • 인덱스는 음수일 수 있습니다.스테이트먼트의 , 모든 부호 타입: 부호 없는 타입)은 과 같습니다.size_t.
  • p2 - p1ptrdiff_t.i == p2 - p1 이렇게 이렇게 나올 수 거예요.p2을을 p2 == p1 + i 「 」에 해 주세요.*(p + i) p[i].
  • 유형 또 로서 "일반 인덱스 유형"이 때 과부하 입니다.operator[]들어 는 사용자가 한 (사용자가 제공하는) 사용자와 합니다.operator[](예를 들어 벡터)는 (http://eel.is/c++draft/over.built#16):>)와 같습니다.

    모든 cv-qualified 또는 cv-qualified 객체 유형 T에 대해 형식의 후보 연산자 함수가 존재한다.

    T*      operator+(T*, std::ptrdiff_t);
    T&      operator[](T*, std::ptrdiff_t);
    T*      operator-(T*, std::ptrdiff_t);
    T*      operator+(std::ptrdiff_t, T*);
    T&      operator[](std::ptrdiff_t, T*);
    

편집: 매우 큰 배열이나 매우 큰 메모리 부분에 대한 포인터가 있는 경우, "일반 인덱스 유형"에서는 잘라내지 않습니다. 그러면 마지막 요소의 주소에서 첫 번째 요소의 주소를 뺄 수 없습니다.@Ciro의 답변은 https://stackoverflow.com/a/31090426/34509에서 사용해야 합니다.개인적으로는 부호가 없는 타입은 음의 엣지 케이스(예를 들어 거꾸로 반복할 때의 루프 엔드 값)를 나타낼 수 없기 때문에 사용하지 않도록 하고 있습니다만, 이것은 일종의 종교적인 논쟁입니다(하지만, 그 캠프에 있는 것은 저뿐만이 아닙니다).서명 없는 활자를 사용해야 하는 경우에는 당연히 종교를 제쳐두어야 합니다.

「 」의 에,sizeof(array) (그리고)malloc의 인수는 「」입니다size_t보다 많은 수 없기 은 그 크기보다 더 많은 요소를 포함할 수 없습니다.그 결과 다음과 같습니다.size_t배열 색인에 사용할 수 있습니다.

편집 이 분석은 일반적인 경우인 0 기반 어레이를 대상으로 합니다. ptrdiff_t어떤 경우에도 작동하지만 인덱스 변수가 포인터 차이 유형을 갖는 것은 조금 이상합니다.

size_t

로 at at로 하는 경우0하다, 사용하다size_t 이 어레이를 수 하기 때문입니다.

  • sizeof이 이을반음음음음음음음음음음음음음음음음음음음음음음음음음음음음음음 returns returns returns 보다 큰 것은 유효하지 않습니다.size_t
  • malloc한 바와 같이 .

하여 0으로 을 사용합니다.size_t이치노체체: :

for (j = jmin; j < jmax; j++) {
    do_something(a[j]);
}

포함:

int *b = &a[jmin];
for (size_t i = 0; i < (jmax - jmin); i++) {
    do_something(b[i]);
}

사용하지 않는 이유:

  • ptrdiff_t: 이 값이 나타내는 최대값은 다음 값보다 작을 수 있습니다.size_t.

    이는 cppref에 기재되어 있으며 어레이가 너무 클 경우 정의되지 않은 동작이 발생할 가능성이 C99 6.5.5/9에 제시되어 있습니다.

    2개의 포인터가 감산되면 양쪽 모두 같은 배열 객체의 요소 또는 배열 객체의 마지막 요소 뒤에 있는 요소를 가리켜야 합니다.그 결과 두 배열 요소의 첨자 차이가 발생합니다.결과의 사이즈는 실장 정의이며, 그 타입(부호 있는 정수 타입)은 헤더에 정의되어 있다.ptrdiff_t결과를 해당 유형의 개체로 나타낼없는 경우 동작은 정의되지 않습니다.

    그러는데intptr_t, 보다 클 도 있습니다.size_t세그먼트 메모리 아키텍처:https://stackoverflow.com/a/1464194/895245

    또한 GCC에서는 스태틱 어레이 객체의 최대 사이즈에 대해 다음과 같은 제한을 가합니다.C에서 어레이의 최대 크기는 얼마입니까?

  • uintptr_t: 잘 모르겠어요.그래서 저는 그냥size_t더 확실하기 때문에 :-)

다음 항목도 참조하십시오.

사용하고 있다unsigned int. (단, 줄임말이 더 좋지만)unsigned)

C99에서는unsigned int는 모든 포터블 어레이를 인덱싱할 수 있음을 보증합니다.65'535바이트 이하의 어레이만 지원되며 최대unsigned int값은 65'535 이상이어야 합니다.

C99 표준의 일반 WG14 N1256 초안:

5.2.4.1 번역 제한

실장에서는 다음 제한 중 적어도1개의 인스턴스를 포함하는 프로그램을 번역 및 실행할 수 있어야 합니다(실장에서는 가능한 한 고정 번역 제한을 부과하지 않도록 합니다).

(...)

  • 오브젝트 내 65535바이트(호스트 환경 내만)

(...)

5.2.4.2 수치 한계

구현은 이 하위 절에 명시된 모든 제한을 문서화하기 위해 필요합니다. 이러한 제한은 헤더에 명시되어 있습니다.<limits.h>그리고.<float.h>. 추가 제한은 에 명시되어 있습니다.<stdint.h>.

5.2.4.2.1 정수형 크기<limits.h>

아래에 제시된 값은 다음에서 사용하기에 적합한 상수 표현으로 대체해야 한다.#if지시 전처리.더군다나, 을 제외하고.CHAR_BIT그리고.MB_LEN_MAX다음은 정수 승진에 따라 변환된 해당 유형의 객체인 식과 동일한 유형의 식으로 대체해야 한다.구현 정의 값은 같은 부호로 표시된 값과 크기(절대 value) 이상이어야 합니다.

(...)

  • 유형 객체의 최대값unsigned int UINT_MAX65535 // 2^16 - 1

C89에서는 최대 포터블 어레이 사이즈는 실제로는 32'767바이트에 불과하기 때문에 서명된 어레이라도int최대값은 32'767(부록 A.4) 이상입니다.

C89 드래프트의 § 2.2.4부터:

2.2.4.1 번역 제한

실장에서는 다음 제한 중 적어도1개의 인스턴스를 포함하는 프로그램을 번역 및 실행할 수 있어야 합니다(실장에서는 가능한 한 고정 번역 제한을 부과하지 않도록 합니다).

(...)

  • 오브젝트 내 32767바이트(호스트 환경 내만)

(...)

2.2.4.2 수치 한계

적합 실장은 이 절에 명시된 모든 제한을 문서화해야 하며, 이는 헤더에 명시되어야 한다.<limits.h>그리고.<float.h>.

"통합형 사이즈<limits.h>"

아래 값은 #if 전처리 지침에서 사용하기에 적합한 상수 표현으로 대체해야 합니다.구현 정의 값은 같은 부호로 표시된 값과 크기(절대값) 이상이어야 합니다.

(...)

  • 유형 int 객체의 최대값INT_MAX +32767

선택 : ptrdiff_t

많은 사람들이 투표했다.ptrdiff_t그러나 일부에서는 포인터 차분 유형을 사용하여 인덱스를 작성하는 것이 이상하다고 말합니다.어레이 인덱스는 원래 포인터와의 차이입니다.

라고 말하는 사람도 있다.size_t사이즈를 유지할 수 있도록 설계되어 있기 때문입니다.그러나 일부에서 코멘트가 있듯이 이는 바이트 단위의 크기이므로 일반적으로 가능한 최대 배열 색인보다 몇 배 큰 값을 유지할 수 있습니다.

당신의 상황이라면, 저는ptrdiff_t지표가 부정적일 수 있다는 것만이 아닙니다.0까지 카운트다운 할 수 있습니다.이 경우, 서명이 끝난 타입에서는, 심술궂고 미묘한 버그가 발생합니다.

for(size_t i=5; i>=0; i--) {
  printf("danger, this loops forever\n);
}

그런 일은 일어나지 않습니다.ptrdiff_t또는 기타 적절한 서명 형식.POSIX 시스템에서는,ssize_t.

저는 개인적으로 그냥...int올바른 방법은 아니지만요.

어레이의 최대 길이를 미리 알고 있다면

  • int_fast*_t / uint_fast*_t
  • int_least*_t / uint_least*_t

다른 모든 경우에는 다음을 사용하는 것이 좋습니다.

  • size_t

또는

  • ptrdiff_t

음의 인덱스를 허용하려는 날씨에 따라 달라집니다.

사용.

  • intptr_t / uintptr_t

안전하지만 의미론도 조금 다릅니다.

나는 주로 사용한다.size_t배열을 오프셋할 수 있지만 음의 배열 인덱스를 작성하려면intC89(32767바이트)가 보증하는 최대 크기 어레이에 대응할 수 있습니다.

C99(65535바이트)가 보증하는 최대 크기의 어레이에 액세스하려면unsigned.

C가 허용하지만 보장하지는 않는 어레이에 대한 액세스는 이전 리비전을 참조하십시오.

언급URL : https://stackoverflow.com/questions/3174850/what-is-the-correct-type-for-array-indexes-in-c

반응형