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
배열과 크기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의 배열에 있는 음의 인덱스에 액세스할 수 있습니다.
그게 뭐였을까요?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개의 콘텍스트로 사용해 왔습니다.
comb[1][-1] = 0을 알려주는 조합 번호 테이블이 있습니다. 테이블에 액세스하기 전에 인덱스를 항상 확인할 수 있지만 이렇게 하면 코드가 더 깔끔하고 빠르게 실행됩니다.
테이블 맨 앞에 센티넬을 놓는다.예를 들어 다음과 같은 것을 사용하고 싶다.
while (x < a[i]) i--;
하지만 그 다음, 당신은 그것을 확인해야 한다.i
양성입니다.
해결 방법: 다음과 같이 합니다.a[-1]
이-DBLE_MAX
,하도록x<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
'programing' 카테고리의 다른 글
사전 목록을 panda DataFrame으로 변환 (0) | 2022.12.26 |
---|---|
부동값이 정수인지 확인하는 방법 (0) | 2022.12.26 |
Mysql 테이블의 필드 설명 표시 (0) | 2022.12.26 |
MySQL의 server-id와 server_id의 차이 (0) | 2022.12.26 |
apk로 컴파일하지 않고 Android 프로젝트를 라이브러리로 Import하는 방법(Android studio 1.0) (0) | 2022.12.26 |