[c] C에서 음의 배열 인덱스가 허용됩니까?

나는 방금 일부 코드를 읽고 그 사람이 arr[-2]다음 arr과 같이 두 번째 요소에 액세스하는 데 사용하고 있음을 발견했습니다 .

|a|b|c|d|e|f|g|
       ^------------ arr[0]
         ^---------- arr[1]
   ^---------------- arr[-2]

허용됩니까?

그 알 arr[x]과 동일합니다 *(arr + x). 그래서 arr[-2]입니다 *(arr - 2)확인을 보인다. 어떻게 생각해?



답변

맞아요. C99 §6.5.2.1 / 2에서 :

아래 첨자 연산자 []의 정의는 E1 [E2]가 (* ((E1) + (E2)))와 동일하다는 것입니다.

마법은 없습니다. 1-1 등가입니다. 포인터 (*)를 역 참조 할 때 항상 그렇듯이 유효한 주소를 가리키고 있는지 확인해야합니다.


답변

이것은 arr배열의 두 번째 요소 또는 이후 요소를 가리키는 포인터 인 경우에만 유효합니다 . 그렇지 않으면 배열 경계 외부의 메모리에 액세스하기 때문에 유효하지 않습니다. 예를 들어 이것은 잘못된 것입니다.

int arr[10];

int x = arr[-2]; // invalid; out of range

그러나 이것은 괜찮을 것입니다.

int arr[10];
int* p = &arr[2];

int x = p[-2]; // valid:  accesses arr[0]

그러나 음의 아래 첨자를 사용하는 것은 드문 경우입니다.


답변

나에게 괜찮아 보인다. 그러나 합법적으로 필요한 경우는 드뭅니다.


답변

아마도 그것은 arr배열의 중간을 arr[-2]가리키고 있었기 때문에 경계를 벗어나지 않고 원래 배열의 무언가를 가리키고 있습니다.


답변

이것이 얼마나 신뢰할 수 있는지는 모르겠지만 64 비트 시스템 (LP64로 추정)에서 음수 배열 인덱스에 대한 다음주의 사항을 읽었습니다. http://www.devx.com/tips/Tip/41349

저자는 64 비트 주소 지정이있는 32 비트 int 배열 색인이 배열 색인이 명시 적으로 64 비트로 승격되지 않는 한 잘못된 주소 계산을 초래할 수 있다고 말하는 것 같습니다 (예 : ptrdiff_t 캐스트를 통해). 나는 실제로 gcc 4.1.0의 PowerPC 버전에서 그의 성격의 버그를 보았지만 그것이 컴파일러 버그인지 (즉, C99 표준에 따라 작동해야하는지) 또는 올바른 동작인지 (즉, 인덱스가 64로 캐스트가 필요한지 모르겠습니다.) 올바른 행동을위한 비트)?


답변

나는 질문에 대한 답을 알고 있지만이 설명을 공유하는 것을 거부 할 수 없었다.

컴파일러 설계의 원리를 기억합니다. a는 int 배열이고 int의 크기는 2이고 a의 기본 주소는 1000이라고 가정하겠습니다.

어떻게 a[5]작동합니다 ->

Base Address of your Array a + (index of array *size of(data type for array a))
Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

이 설명은 배열의 음수 인덱스가 C에서 작동하는 이유이기도합니다.

즉 내가 액세스 a[-5]하면 나에게 줄 것입니다

Base Address of your Array a + (index of array *size of(data type for array a))
Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

위치 990에서 객체를 반환합니다.이 논리에 따라 C의 Array에있는 음수 인덱스에 액세스 할 수 있습니다.


답변

누군가 음수 인덱스를 사용하려는 이유에 대해 두 가지 컨텍스트에서 사용했습니다.

  1. comb [1] [-1] = 0을 알려주는 조합 번호 테이블을 가지고 있습니다. 테이블에 액세스하기 전에 항상 인덱스를 확인할 수 있지만 이렇게하면 코드가 더 깔끔해 보이고 더 빠르게 실행됩니다.

  2. 테이블의 시작 부분에 센티넬을 넣습니다. 예를 들어, 다음과 같은 것을 사용하고 싶습니다.

     while (x < a[i]) i--;

하지만 i긍정적 인지도 확인해야합니다 .
해결 방법 : 그 있도록 할 a[-1]것입니다 -DBLE_MAX그 때문에, x&lt;a[-1]항상 false가 될 것입니다.