programing

C에서는 마이너스 어레이 인덱스를 사용할 수 있습니까?

newsource 2022. 12. 26. 20:29

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 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]

그러나 음의 첨자를 사용하는 것은 드문 일이다.

난 괜찮을 것 같아.하지만 합법적으로 필요한 경우는 드물 것입니다.

질문에 답한 건 알지만, 이 설명을 공유하지 않을 수 없었다.

컴파일러 설계의 원리:가정해 봅시다a는 입니다.int배열과 크기int2및 의 베이스 주소a1000.

어떻게 할 것인가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의 배열에 있는 음의 인덱스에 액세스할 수 있습니다.

그게 뭐였을까요?arr어레이의 중앙을 가리키고 있었기 때문에arr[-2]범위를 벗어나지 않고 원래 배열의 무언가를 가리킵니다.

#include <stdio.h>

int main() // negative index
{ 
    int i = 1, a[5] = {10, 20, 30, 40, 50};
    int* mid = &a[5]; //legal;address,not element there
    for(; i < 6; ++i)
    printf(" mid[ %d ] = %d;", -i, mid[-i]);
}

음의 인덱스를 사용하는 이유에 대해서는, 다음의 2개의 콘텍스트로 사용해 왔습니다.

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

  2. 테이블 맨 앞에 센티넬을 놓는다.예를 들어 다음과 같은 것을 사용하고 싶다.

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

하지만 그 다음, 당신은 그것을 확인해야 한다.i양성입니다.
해결 방법: 다음과 같이 합니다.a[-1]-DBLE_MAX,하도록x&lt;a[-1]항상 거짓일 것이다.

이것이 얼마나 신뢰할 수 있는지는 모르겠습니다만, 64비트 시스템의 마이너스 어레이 인덱스에 관한 다음의 경고를 읽었습니다(LP64로 추정).http://www.devx.com/tips/Tip/41349

저자는 어레이 인덱스를 64비트로 명시적으로 승격하지 않는 한(예를 들어 ptrdiff_t 캐스트를 통해) 64비트 어드레싱을 사용하는 32비트 int 어레이 인덱스가 잘못된 주소 계산을 초래할 수 있다고 말합니다.실제로 GCC 4.1.0의 PowerPC 버전에서 그와 같은 버그를 본 적이 있지만 컴파일러 버그(C99 표준에 따라 동작해야 함)인지 올바른 동작(인덱스가 올바른 동작을 위해 64비트에 대한 캐스트 필요)인지 알 수 없습니다.

예를 들어 보겠습니다.

GNU C++ 라이브러리 basic_string.h

[주의: 이것은 "C++"의 예라고 누군가 지적하고 있기 때문에 이 "C"의 주제에는 적합하지 않을 수 있습니다.나는 예시와 같은 개념의 "C" 코드를 쓴다.적어도 GNU gcc 컴파일러는 불평하지 않습니다.]

[-1]을 사용하여 사용자 문자열에서 관리 정보 블록으로 포인터를 다시 이동합니다.충분한 용량으로 메모리를 한 번 할당하기 때문입니다.

「*이 어프로치에서는, 문자열 오브젝트*에 할당이 1개만 필요한 것이 큰 메리트가 있습니다.모든 추악성은 *이(가) 인라인 함수의 단일 %pa 쌍 내에서 제한됩니다.각 함수는 *1개의 @a 추가 명령으로 컴파일됩니다._Rep::_M_data() 및 * 문자열:_M_rep(); 및 할당 함수는 *의 raw 바이트 블록을 가져오고 충분한 공간을 확보하여 전면에 _Rep * 개체를 구성합니다."

소스 코드: https://gcc.gnu.org/onlinedocs/gcc-10.3.0/libstdc++/api/a00332_source.html

   struct _Rep_base
   {
     size_type               _M_length;
     size_type               _M_capacity;
     _Atomic_word            _M_refcount;
   };

   struct _Rep : _Rep_base
   {
      ...
   }

  _Rep*
   _M_rep() const _GLIBCXX_NOEXCEPT
   { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }

설명:

*  A string looks like this:
*
*  @code
*                                        [_Rep]
*                                        _M_length
*   [basic_string<char_type>]            _M_capacity
*   _M_dataplus                          _M_refcount
*   _M_p ---------------->               unnamed array of char_type
*  @endcode
*
*  Where the _M_p points to the first character in the string, and
*  you cast it to a pointer-to-_Rep and subtract 1 to get a
*  pointer to the header.
*
*  This approach has the enormous advantage that a string object
*  requires only one allocation.  All the ugliness is confined
*  within a single %pair of inline functions, which each compile to
*  a single @a add instruction: _Rep::_M_data(), and
*  string::_M_rep(); and the allocation function which gets a
*  block of raw bytes and with room enough and constructs a _Rep
*  object at the front.
*
*  The reason you want _M_data pointing to the character %array and
*  not the _Rep is so that the debugger can see the string
*  contents. (Probably we should add a non-inline member to get
*  the _Rep for the debugger to use, so users can check the actual
*  string length.)
*
*  Note that the _Rep object is a POD so that you can have a
*  static <em>empty string</em> _Rep object already @a constructed before
*  static constructors have run.  The reference-count encoding is
*  chosen so that a 0 indicates one reference, so you never try to
*  destroy the empty-string _Rep object.
*
*  All but the last paragraph is considered pretty conventional
*  for a C++ string implementation.

// 이전 개념을 사용하여 샘플 C 코드를 작성합니다.

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

typedef struct HEAD {
    int f1;
    int f2;
}S_HEAD;

int main(int argc, char* argv[]) {
    int sz = sizeof(S_HEAD) + 20;

    S_HEAD* ha = (S_HEAD*)malloc(sz);
    if (ha == NULL)
      return -1;

    printf("&ha=0x%x\n", ha);

    memset(ha, 0, sz);

    ha[0].f1 = 100;
    ha[0].f2 = 200;

    // move to user data, can be converted to any type
    ha++;
    printf("&ha=0x%x\n", ha);

    *(int*)ha = 399;

    printf("head.f1=%i head.f2=%i user data=%i\n", ha[-1].f1, ha[-1].f2, *(int*)ha);

    --ha;
    printf("&ha=0x%x\n", ha);

    free(ha);

    return 0;
}



$ gcc c1.c -o c1.o -w
(no warning)
$ ./c1.o 
&ha=0x13ec010
&ha=0x13ec018
head.f1=100 head.f2=200 user data=399
&ha=0x13ec010

도서관 작성자가 사용합니다.도움이 되길 바랍니다.

언급URL : https://stackoverflow.com/questions/3473675/are-negative-array-indexes-allowed-in-c