IntPtr은 정확히 무엇입니까?


171

IntelliSense를 사용하고 다른 사람들의 코드를 살펴보면서이 IntPtr유형을 보았습니다. 그것이 필요할 때마다 나는 단순히 작동하는 대부분의 기능을 null넣거나 IntPtr.Zero발견했습니다. 정확히 무엇이며 언제 / 왜 사용됩니까?

답변:


158

"기본 (플랫폼 별) 크기 정수"입니다. 내부적으로 표현 void*되었지만 정수로 노출되어 있습니다. 관리되지 않는 포인터를 저장해야하고 unsafe코드 를 사용하고 싶지 않을 때마다 사용할 수 있습니다 . IntPtr.Zero효과적으로 NULL(널 포인터)입니다.


53
포인터는 메모리의 주소를 가리키는 것입니다. 관리되는 언어에는 참조가 있고 (주소는 이동할 수 있습니다) 관리되지 않는 언어에는 포인터가 있습니다 (주소는 고정되어 있음)
Colin Mackay

93
일반적으로 (프로그래밍 언어에서) 포인터는 메모리의 물리적 위치를 나타내는 숫자입니다. 포인터는 점 0 (거의 항상)이며, 널리 "아무것도 가리 키지"로 인식됩니다. 시스템은 지원되는 메모리 양이 다르기 때문에 항상 같은 수의 바이트를 사용하여 해당 숫자를 보유하지는 않으므로 특정 시스템에서 포인터를 보유 할 수있는 "기본 크기 정수"를 호출합니다.
Sam Harwell

5
그 의견 @ 280Z28에 +1, 그것은 내가 본 포인터에 대한 가장 간결한 설명입니다.
BlueRaja-대니 Pflughoeft

9
관리되지 않는 네이티브 코드 C / C ++에서 사용하려면 intptr_t라는 아날로그 형식을 사용해야하므로 IntPtr이라고합니다. C #의 IntPtr은 C / C ++의 intptr_t에 정확하게 매핑됩니다. 그리고 아마도 intptr_t로 구현되었을 것입니다. C / C ++에서 intptr_t 유형은 void * 유형과 동일한 크기를 보장합니다.
Петър Петров

2
@Trap "포인터 또는 핸들을 나타내는 데 사용되는 플랫폼 별 유형." "플랫폼 특정 정수"가 아니라 "포인터 또는 핸들을 나타내는 플랫폼 특정 방법". IntPtr정수 (수학적 정수)와 포인터 (포인터)이기 때문에 완벽하게 이해됩니다. 이 Int부분은 int 유형과 거의 관련이 없습니다. 특정 유형이 아니라 개념입니다. 공평하지만 CLI 사양에 따르면 "정수, 기본 크기"라는 것이 유일한 것입니다. Oh well :)
Luaan

69

네이티브 또는 안전하지 않은 코드에서 사용되는 메모리 주소를 저장할 수있을만큼 큰 값 유형이지만 안전한 관리 코드에서 메모리 주소로 직접 사용할 수는 없습니다.

당신은 사용할 수 IntPtr.Size는 각각 4 또는 8 바이트를 수있는 바와 같이, 32 비트 또는 64 비트 프로세스에서 실행하고 있는지 알 수 있습니다.


16
프로세스의 주소 공간 크기를 감지하는 것이 좋습니다.
Noldorin

@Noldorin True이지만 반드시 신뢰할 필요는 없습니다. 과거에는 여러 포인터 유형을 가진 아키텍처가 많았으며 Windows에서는 IntPtr아키텍처에 관계없이 32 비트 인 핸들을 나타내는 데에도 사용되었습니다 ( Size이 경우 여전히 8이라고 함). CLI 스펙은 "네이티브 크기"인 정수이지만 실제로는별로 언급하지 않는 정수입니다.
Luaan

내 대답에서 실제로 아무것도 변경하지 않는 @Luaan이 그렇게합니까? IntPtr은 메모리 주소를 보유하기에 충분한 값으로 소위 호출됩니다 (CLR 소스 전체에서 사용됨). 물론 더 작은 값을 보유 할 수 있습니다. 일부 아키텍처에는 여러 포인터 유형이 있지만 세트 중 가장 큰 포인터 유형이 있어야합니다.
Daniel Earwicker

@DanielEarwicker 글쎄, 내가 아는 한, 현재 .NET 구현에는 문제가되지 않습니다. 그러나 (역사적) 문제는 크기에 국한되지 않으며 다양한 포인터가 완전히 호환되지 않을 수 있습니다. 오늘날에 가까운 예에서 PAE는 "기본 포인터 크기"가 여전히 32 비트이지만 64 비트 주소를 사용합니다. "32 비트 시스템은 무엇을 의미 하는가?"라는 주장으로 거슬러 올라갑니다. 현재 256 비트 및 512 비트 숫자 레지스터가 있지만 여전히 64 비트라고합니다. 실제로 64 비트 "포인터"로 64 비트의 실제 메모리를 처리 할 수는 없습니다 . 엉망입니다.
Luaan

1
일부는 복잡하지만 IntPtr은 여전히 ​​"메모리 주소를 저장할만큼 큰 값 유형"입니다. 예제 중 하나를 취하는 것은 가장 큰 하드웨어 레지스터만큼 크지 않습니다. 그것은 단지 그것이 목적이 아닙니다. 메모리 주소를 표현하기에 충분히 큽니다. 다음과 같은 것들이 있습니다 : stackoverflow.com/questions/12006854/… 여기서 우리는 "포인터"라는 단어가 메모리 주소 이외의 다른 단어로 사용되고 있습니다.
Daniel Earwicker

48

예를 들면 다음과 같습니다.

고속 카메라와 인터페이스하는 C # 프로그램을 작성 중입니다. 카메라에는 이미지를 가져 와서 자동으로 컴퓨터 메모리에로드하는 자체 드라이버가 있습니다.

따라서 최신 이미지를 작업 할 프로그램으로 가져올 준비가되면 카메라 드라이버가 이미지를 물리적 메모리에 이미 저장되어있는 위치에 IntPtr을 제공하므로 시간 / 자원을 낭비하지 않아도됩니다. 이미 메모리에있는 이미지를 저장하기위한 메모리 블록. IntPtr은 이미지가 이미 어디에 있는지 보여줍니다.


7
따라서 IntPtr을 사용하면 관리 코드에서 관리되지 않는 포인터 (예 : 카메라 드라이버에서 사용되는 것과 같은)를 사용할 수 있습니까?
Callum Rogers

5
예. 이 경우 카메라 드라이버는 후드 아래에서 관리되지 않는 드라이버를 사용하지만 대부분 Managed-only 세계에서 제대로 작동하려면 데이터를 안전하게 사용할 수있는 IntPtr을 제공합니다.
bufferz

3
그렇다면 왜 스트림 (바이트 배열)을 다시 제공하지 않습니까? 왜 안전하지 않거나 값을 반환 할 수 없습니까?
머핀 맨

35

직접적인 해석

을 IntPtr은정수 A와 같은 크기의 포인터 .

IntPtr을 사용하여 포인터가 아닌 유형으로 포인터 값을 저장할 수 있습니다. 포인터를 사용하면 오류가 발생하기 쉬우므로 대부분의 상황에서 불법이기 때문에이 기능은 .NET에서 중요합니다. 포인터 값을 "안전한"데이터 형식으로 저장하면 안전 하지 않은 코드 세그먼트 간의 배관 이보다 안전한 고급 코드 또는 포인터를 직접 지원하지 않는 .NET 언어로 구현 될 수 있습니다.

IntPtr의 크기는 플랫폼에 따라 다르지만 시스템에서 자동으로 올바른 크기를 사용하므로이 세부 사항을 고려할 필요가 거의 없습니다.

"IntPtr"이라는 이름이 혼동 Handle됩니다. 더 적절할 수도 있습니다. 내 초기 추측 "을 IntPtr은"포인터이었다이었다 정수. IntPtrMSDN 설명서 는 이름의 의미에 대한 통찰력을 제공하지 않으면 서 다소 비밀리에 자세히 설명합니다.

다른 관점

IntPtr두 가지 제한이있는 포인터입니다 :

  1. 직접 역 참조 할 수 없습니다
  2. 가리키는 데이터 유형을 모릅니다.

다시 말해, IntPtra는 void*- 와 비슷 하지만 기본 포인터 산술에 사용할 수있는 추가 기능이 있습니다.

의 참조를 역 참조하기 위해 IntPtr실제 포인터 ( "안전하지 않은"컨텍스트에서만 수행 할 수있는 작업)로 캐스트하거나 InteropServices.Marshal클래스에서 제공하는 것과 같은 도우미 루틴으로 전달할 수 있습니다 . Marshal클래스를 사용하면 명시적인 "안전하지 않은"컨텍스트에있을 필요가 없으므로 안전에 대한 환상을 갖게됩니다. 그러나 포인터 사용에 따른 충돌 위험을 제거하지는 않습니다.


2
"C"프로그래밍 언어의 C99 표준에서 "intptr"이라는 이름에 대한 선례가 있습니다. linux.die.net/man/3/intptr_t .
브렌트 브래드 번

17

포인터 란 무엇입니까?

모든 언어에서 포인터는 메모리 주소를 저장하는 변수 유형이며, 가리키는 주소 또는 가리키는 주소 을 알려줄 수 있습니다 .

포인터는 일종의 북 마크라고 생각할 수 있습니다. 책의 한 페이지로 빠르게 이동하는 대신 포인터를 사용하여 메모리 블록을 추적하거나 매핑합니다.

프로그램의 메모리가 65535 바이트의 큰 배열과 정확히 같다고 상상해보십시오.

포인터가 순종적으로 가리킨다

포인터는 각각 하나의 메모리 주소를 기억하므로 각각 메모리의 단일 주소를 가리 킵니다.

그룹으로서, 포인터는 모든 명령 광고 구역에 따라 메모리 주소를 기억하고 기억합니다.

당신은 그들의 왕입니다.

C #의 포인터

특히 C #에서 포인터는 0에서 65534 사이의 메모리 주소를 저장하는 정수 변수입니다.

또한 C #과 관련하여 포인터는 int 유형이므로 서명됩니다.

음수로 된 주소는 사용할 수 없으며 65534보다 높은 주소에는 액세스 할 수 없습니다. 그렇게하면 System.AccessViolationException이 발생합니다.

MyPointer 라는 포인터 는 다음과 같이 선언됩니다.

int * MyPointer;

C #의 포인터는 int이지만 C #의 메모리 주소는 0에서 시작하여 65534까지 확장됩니다.

뾰족한 물건은 특별한주의를 기울여 처리해야합니다.

안전하지 않은 단어 당신을 놀라게하기위한 것입니다. 아주 좋은 이유는 다음과 같습니다. 포인터는 뾰족한 물건이며 칼, 축, 포인터 등과 같은 뾰족한 물건은 특별한주의를 기울여 다루어야합니다.

포인터는 프로그래머에게 시스템을 엄격하게 제어합니다. 따라서 실수는 더 심각한 결과를 초래할 수 있습니다.

포인터를 사용하려면 프로그램 속성에서 안전하지 않은 코드를 활성화해야하며 안전하지 않은 것으로 표시된 메서드 나 블록에서만 포인터를 사용해야합니다.

안전하지 않은 블록의 예

unsafe
{
    // Place code carefully and responsibly here.

}

포인터 사용법

변수 나 객체가 선언되거나 인스턴스화되면 메모리에 저장됩니다.

  • * 기호 접두사를 사용하여 포인터를 선언하십시오.

int *MyPointer;

  • 변수의 주소를 얻으려면 & 기호 접두사를 사용하십시오.

MyPointer = &MyVariable;

주소가 포인터에 할당되면 다음이 적용됩니다.

  • * 접두사가 없으면 int로 가리키는 메모리 주소를 나타냅니다.

MyPointer = &MyVariable; // Set MyPointer to point at MyVariable

  • * 접두사를 사용하여 가리키는 메모리 주소에 저장된 값을 가져옵니다.

"MyPointer is pointing at " + *MyPointer;

포인터는 메모리 주소를 보유하는 변수이므로이 메모리 주소는 포인터 변수에 저장 될 수 있습니다.

신중하고 책임감있게 사용되는 포인터의 예

    public unsafe void PointerTest()
    {
        int x = 100; // Create a variable named x

        int *MyPointer = &x; // Store the address of variable named x into the pointer named MyPointer

        textBox1.Text = ((int)MyPointer).ToString(); // Displays the memory address stored in pointer named MyPointer

        textBox2.Text = (*MyPointer).ToString(); // Displays the value of the variable named x via the pointer named MyPointer.

    }

포인터의 타입은 int입니다. C #이 메모리 주소를 정수 (int)로 해석하기 때문입니다.

왜 uint 대신 int입니까?

정당한 이유가 없습니다.

왜 포인터를 사용합니까?

포인터는 많은 재미입니다. 컴퓨터의 많은 부분이 메모리로 제어되므로 포인터는 프로그래머가 프로그램 메모리를보다 잘 제어 할 수 있도록합니다.

메모리 모니터링.

포인터를 사용하여 메모리 블록을 읽고 시간이 지남에 따라 값이 변경되는 방식을 모니터링하십시오.

책임감있게 이러한 값을 변경하고 변경 사항이 컴퓨터에 미치는 영향을 추적하십시오.


2
65534포인터 범위로 매우 잘못된 것 같습니다. 참조를 제공해야합니다.
브렌트 브래드 번

1
포인터를 설명하는 훌륭한 기사이기 때문에 이것을 투표했습니다. 위에서 언급 한 사양에 대한 언급을하고 싶습니다. 하나; 이 답변은 질문과 관련이 없습니다. 문제는에 관한 것이었다 System.IntPtr. System.IntPtrC #에서 안전하지 않은 포인터와 관련이있는 방법과 설명이 마지막에 업데이트 된 답변을보고 싶습니다 .
Michael Puckett II

7

MSDN은 다음과 같이 말합니다.

IntPtr 형식은 크기가 플랫폼에 따라 다른 정수로 설계되었습니다. 즉,이 유형의 인스턴스는 32 비트 하드웨어 및 운영 체제에서 32 비트이고 64 비트 하드웨어 및 운영 체제에서 64 비트 일 것으로 예상됩니다.

IntPtr 형식은 포인터를 지원하는 언어로, 포인터를 지원하거나 지원하지 않는 언어 간의 데이터를 참조하는 일반적인 수단으로 사용할 수 있습니다.

IntPtr 객체를 사용하여 핸들을 유지할 수도 있습니다. 예를 들어 IntPtr의 인스턴스는 System.IO.FileStream 클래스에서 광범위하게 사용되어 파일 핸들을 보유합니다.

IntPtr 유형은 CLS 규격이지만 UIntPtr 유형은 아닙니다. 공용 언어 런타임에서는 IntPtr 형식 만 사용됩니다. UIntPtr 유형은 대부분 IntPtr 유형과 구조적 대칭을 유지하기 위해 제공됩니다.

http://msdn.microsoft.com/en-us/library/system.intptr(VS.71).aspx


5

글쎄, 이것은 다루는 MSDN 페이지 입니다 IntPtr.

첫 번째 줄은 다음과 같습니다.

포인터 또는 핸들을 나타내는 데 사용되는 플랫폼 별 유형입니다.

포인터 또는 핸들이 무엇인지에 대해 페이지는 상태로 진행됩니다.

IntPtr 형식은 포인터를 지원하는 언어로, 포인터를 지원하거나 지원하지 않는 언어 간의 데이터를 참조하는 일반적인 수단으로 사용할 수 있습니다.

IntPtr 객체를 사용하여 핸들을 유지할 수도 있습니다. 예를 들어 IntPtr의 인스턴스는 System.IO.FileStream 클래스에서 광범위하게 사용되어 파일 핸들을 보유합니다.

포인터는 관심있는 일부 데이터를 보유하는 메모리 영역에 대한 참조입니다.

핸들은 객체의 식별자 일 수 있으며 양쪽이 해당 객체에 액세스해야 할 때 메서드 / 클래스간에 전달됩니다.


2

IntPtrA는 치형 주로 홀드 메모리 어드레스 나 핸들에 사용된다. 포인터는 메모리 주소입니다. 포인터는 입력 (예 int*:) 또는 입력 되지 않은 (예 :) 일 수 있습니다 void*. 윈도우 핸들은 일반적으로 메모리 주소와 같은 크기 (이하)이며, (파일이나 창 같은) 시스템 자원을 나타내는 값이다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.