수색…


비고

포인터 및 unsafe

포인터의 성격으로 인해 포인터는 검증 할 수없는 코드를 생성합니다. 따라서 모든 포인터 유형을 사용하려면 unsafe 컨텍스트가 필요합니다.

System.IntPtr 형식은 void* 주위의 안전한 래퍼입니다. 당면 과제를 수행하기 위해 안전하지 않은 컨텍스트가 필요하지 않은 경우 void* 대한보다 편리한 대안으로 사용됩니다.

정의되지 않은 동작

C 및 C ++ 에서처럼 포인터의 잘못된 사용은 정의되지 않은 동작을 호출 할 수 있으며 가능한 부작용은 메모리 손상 및 의도하지 않은 코드 실행입니다. 대부분의 포인터 연산의 검증 할 수없는 특성으로 인해 포인터의 올바른 사용은 전적으로 프로그래머의 책임입니다.

포인터를 지원하는 유형

C 및 C ++과 달리 모든 C # 유형에는 해당 포인터 유형이 없습니다. 다음 두 조건이 모두 적용되면 형식 T 는 해당 포인터 유형을 가질 수 있습니다.

  • T 는 구조체 유형 또는 포인터 유형입니다.
  • T 는 이러한 기준을 모두 재귀 적으로 충족시키는 구성원 만 포함합니다.

배열 액세스를위한 포인터

이 예제는 C # 배열에 대한 C와 같은 액세스를 위해 포인터를 사용하는 방법을 보여줍니다.

unsafe
{
    var buffer = new int[1024];
    fixed (int* p = &buffer[0])
    {
        for (var i = 0; i < buffer.Length; i++)
        {
            *(p + i) = i;
        }
    }
}

포인터 액세스는 일반적으로 C # 배열에 액세스 할 때 일반적으로 발생하는 범위 검사를 내 보내지 않으므로 unsafe 키워드가 필요합니다.

fixed 키워드는 C # 컴파일러에게 예외적 인 방식으로 객체를 고정하는 명령을 내 보내야한다고 알려줍니다. 가비지 컬렉터가 배열을 메모리에서 이동하지 않도록 보장하려면 배열에서 가리키는 포인터를 무효화해야하므로 고정해야합니다.

포인터 연산

포인터의 더하기 및 빼기는 정수와 다르게 작동합니다. 포인터가 증가하거나 감소 할 때 포인터가 가리키는 주소는 지시 대상 유형의 크기만큼 증가되거나 감소됩니다.

예를 들어, int ( System.Int32 별칭) 형식의 크기는 4입니다. int 를 주소 0에 저장할 수 있으면 후속 int 를 주소 4에 저장할 수 있습니다. 코드에서 :

var ptr = (int*)IntPtr.Zero;
Console.WriteLine(new IntPtr(ptr)); // prints 0
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 4
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 8

마찬가지로 long ( System.Int64 별칭) 형식의 크기는 8입니다. long 을 주소 0에 저장할 수 있으면 후속 long 을 주소 8에 저장할 수 있습니다. 코드에서 :

var ptr = (long*)IntPtr.Zero;
Console.WriteLine(new IntPtr(ptr)); // prints 0
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 8
ptr++;
Console.WriteLine(new IntPtr(ptr)); // prints 16

void 유형은 특별하며 void 포인터도 특수하며 유형을 알 수 없거나 중요하지 않을 때 catch-all 포인터로 사용됩니다. Size-Agnostic 특성으로 인해 void 포인터는 증가 또는 감소 할 수 없습니다.

var ptr = (void*)IntPtr.Zero;
Console.WriteLine(new IntPtr(ptr));
ptr++; // compile-time error
Console.WriteLine(new IntPtr(ptr));
ptr++; // compile-time error
Console.WriteLine(new IntPtr(ptr));

별표는 유형의 일부입니다.

C 및 C ++에서 포인터 변수 선언의 별표 (*)는 선언 되는 표현식의 일부입니다 . C #에서는 선언의 별표 가 해당 유형의 일부입니다 .

C, C ++ 및 C #에서 다음 코드 조각은 int 포인터를 선언합니다.

int* a;

C 및 C ++에서 다음 스 니펫은 int 포인터와 int 변수를 선언합니다. C #에서는 두 개의 int 포인터를 선언합니다.

int* a, b; 

C와 C ++에서 다음 스 니펫은 두 개의 int 포인터를 선언합니다. C #에서는 유효하지 않습니다.

int *a, *b;

빈*

C #은 C 및 C ++에서 void* 유형에 상관없이 사용하고 크기를 인식하지 않는 포인터로 상속합니다.

void* ptr;

암시 적 변환을 사용하여 모든 포인터 유형을 void* 할당 할 수 있습니다.

int* p1 = (int*)IntPtr.Zero;
void* ptr = p1;

반대의 경우에는 명시적인 변환이 필요합니다.

int* p1 = (int*)IntPtr.Zero;
void* ptr = p1;
int* p2 = (int*)ptr;

회원 액세스 ->

C #은 C 및 C ++에서 기호 사용을 상속합니다. -> 형식화 된 포인터를 통해 인스턴스 멤버에 액세스하는 수단으로 사용됩니다.

다음 구조체를 고려하십시오.

struct Vector2
{
    public int X;
    public int Y;
}

다음은 회원에 액세스하기 위해 -> 사용의 예입니다.

Vector2 v;
v.X = 5;
v.Y = 10;

Vector2* ptr = &v;
int x = ptr->X;
int y = ptr->Y;
string s = ptr->ToString();

Console.WriteLine(x); // prints 5
Console.WriteLine(y); // prints 10
Console.WriteLine(s); // prints Vector2

일반 포인터

포인터를 지원하기 위해 타입이 만족해야만하는 기준 ( 비고 참조)은 일반적인 제약 조건으로 표현 될 수 없다. 따라서 제네릭 형식 매개 변수를 통해 제공된 형식에 대한 포인터를 선언하려는 시도는 실패합니다.

void P<T>(T obj) 
    where T : struct
{
    T* ptr = &obj; // compile-time error
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow