IntPtrとは正確には何ですか?


171

IntelliSenseを使用して他の人のコードを見ると、このIntPtrタイプに遭遇しました。使用する必要があるたびに、ほとんどの機能が機能するnullIntPtr.Zero、または機能を見つけるだけで済みます。それは正確には何ですか、いつ/なぜ使用されますか?

回答:


158

「ネイティブ(プラットフォーム固有)サイズの整数」です。内部的にはとして表されますvoid*が、整数として公開されます。アンマネージポインターを格納する必要があり、unsafeコードを使用したくない場合はいつでも使用できます。IntPtr.Zeroは効果的ですNULL(nullポインター)。


53
ポインタは、メモリ内のアドレスを指すものです。管理された言語では参照(アドレスは移動できます)がありますが、管理されていない言語ではポインタ(アドレスは固定されています)があります
Colin Mackay

93
一般に(プログラミング言語全体で)、ポインターはメモリ内の物理的な場所を表す数値です。ヌルポインタは、そのポイントを0に(ほとんど常に)一つであり、広く「何を指していない」として認識されています。システムでサポートされるメモリの量は異なるため、その数を保持するために常に同じバイト数を使用するわけではないため、特定のシステムでポインタを保持できる「ネイティブサイズの整数」と呼びます。
サムハーウェル、

5
そのコメントの+1 @ 280Z28は、これまでに見たポインタの最も簡潔な説明です。
BlueRaja-Danny Pflughoeft 2010

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仕様がそれについて言う唯一のことは、それが実際に「整数、ネイティブサイズ」であるということです。まあ:)
Luaan

69

これは、ネイティブまたは安全でないコードで使用されるメモリアドレスを格納するのに十分な大きさの値型ですが、安全なマネージコードでメモリアドレスとして直接使用することはできません。

IntPtr.Sizeそれぞれ4バイトまたは8バイトになるため、32ビットプロセスで実行しているか64ビットプロセスで実行しているかを確認するために使用できます。


16
プロセスのアドレス空間のサイズを検出することについての良い点。
ノルドリン2009

@Noldorin真ですが、必ずしも信頼できるとは限りません。過去には、複数のポインタ型を持つアーキテクチャがたくさんありました。Windowsでは、IntPtrアーキテクチャに関係なく32ビットのハンドルを表すためにも使用されます(ただしSize、この場合は8と表示されます)。CLI仕様では、これが「ネイティブサイズ」の整数であることのみが記載されていますが、実際にはあまり意味がありません。
Luaan

私の答えで本当に何も変更しない@Luaanはそれをしますか?IntPtrは、メモリアドレスを保持するのに十分な大きさの値として、いわゆる(CLRソース全体で使用されます)。もちろん、より小さな値を保持できます。一部のアーキテクチャには複数のポインタタイプがありますが、セットの中で最大のものを必要とします。
Daniel Earwicker 2016

@DanielEarwickerさて、私が知っている限り、現在の.NET実装には問題はありません。ただし、(歴史的な)問題はサイズだけではありません-さまざまなポインターが完全に互換性がない可能性があります。今日に近い例では、「ネイティブポインターサイズ」がまだ32ビットであっても、PAEは64ビットアドレスを使用します。「「32ビットシステム」とはどういう意味ですか?」という議論にまでさかのぼります。現在256ビットと512ビットの数値レジスターがありますが、それでも64ビットと呼んでいます。64ビットの "ポインタ"で64ビットの物理メモリを実際にアドレス指定することはできませんが。それは混乱です。
Luaan 2016

1
一部は複雑ですが、IntPtrは「メモリアドレスを格納するのに十分な大きさの値型」です。例の1つを取ると、最大のハードウェアレジスタほど大きくはありません。それだけではありません。メモリアドレスを表すのに十分な大きさです。次に、次のようなものがあります:stackoverflow.com/questions/12006854/…ここで、「ポインター」という単語がメモリアドレス以外の何かに使用されています-これが、私が特に「メモリアドレス」と言った理由です。
Daniel Earwicker

48

次に例を示します。

高速カメラとインターフェースするC#プログラムを書いています。カメラには、画像を取得してコンピューターのメモリに自動的に読み込む独自のドライバーがあります。

したがって、最新の画像をプログラムに取り込んで作業する準備ができたら、カメラドライバーは、画像がどこに物理メモリに保存されているかを示すIntPtrを提供するので、時間やリソースを無駄にして別の画像を作成する必要がありません。すでにメモリにある画像を保存するためのメモリブロック。IntPtrは、画像がすでにどこにあるかを表示するだけです。


7
したがって、IntPtrシンプルを使用すると、マネージコードでアンマネージポインター(カメラドライバーで使用されているポインターなど)を使用できますか。
Callum Rogers、

5
はい。この場合、おそらく、カメラドライバーは内部でアンマネージドライバーを使用しますが、マネージドのみの世界で適切に動作するために、データを安全に操作できるようにIntPtrを提供します。
bufferz 2009

3
では、なぜストリーム(バイト配列)を返さないのでしょうか。安全ではない、または値を返すことができないのはなぜですか?
マフィンマン2014

35

直接的な解釈

AN のIntPtrである整数と同じサイズであるポインタ

IntPtrを使用して、ポインター値を非ポインター型に格納できます。ポインタを使用するとエラーが発生しやすくなるため、この機能は.NETで重要です。ポインター値を「安全な」データ型で格納できるようにすることで、安全でないコードセグメント間の配管を、より安全な高レベルのコードで実装できます。また、ポインターを直接サポートしていない.NET言語でも実装できます。

IntPtrのサイズはプラットフォーム固有ですが、システムが自動的に正しいサイズを使用するため、この詳細を考慮する必要はほとんどありません。

「IntPtr」という名前は紛らわしい-のようなものHandleがより適切であったかもしれない。私の最初の推測は、 "IntPtr"は整数のポインターであったということでした。IntPtrMSDNドキュメントは、名前の意味についての洞察をこれまで提供することなく、いくぶん不可解な詳細を説明しています。

別の視点

an IntPtrは、2つの制限があるポインターです。

  1. 直接逆参照することはできません
  2. それが指しているデータのタイプを知りません。

言い換えれば、an IntPtrはaと同じですが、void*基本的なポインタ演算に使用できる(ただし、使用してはならない)追加機能があります。

を逆参照するにはIntPtr、それをtrueポインター(「安全でない」コンテキストでのみ実行できる操作)にキャストするか、InteropServices.Marshalクラスによって提供されるようなヘルパールーチンに渡すことができます。Marshalクラスを使用すると、明示的な「安全でない」コンテキストにいる必要がないため、安全であるかのように見えます。ただし、ポインターの使用に固有のクラッシュのリスクは排除されません。


2
「C」プログラミング言語のC99標準からの名前「intptr」にはいくつかの前例があります。linux.die.net/man/3/intptr_t
ブレントブラッドバーン、2010年

17

ポインターとは何ですか?

すべての言語で、ポインターはメモリアドレスを格納する変数の一種であり、ポインターが指しているアドレスまたはポインターが指しているアドレスを通知するように要求できます。

ポインタは、一種のブックマークと考えることができます。例外として、本のページにすばやくジャンプするために使用される代わりに、メモリのブロックを追跡またはマップするためにポインタが使用されます。

プログラムのメモリを65535バイトの1つの大きな配列のように正確に想像してください。

ポインタが素直に指す

ポインタはそれぞれ1つのメモリアドレスを記憶しているため、メモリ内の単一のアドレスをそれぞれポイントします。

グループとして、ポインターはメモリアドレスを記憶および呼び出し、すべてのコマンドと悪心に従います。

あなたは彼らの王です。

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.IntPtr、C#の安全でないポインタに何がどのように関連しているかを説明してください。
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

アンは、IntPtrある値型、主にホールドメモリアドレスまたはハンドルに使用されています。ポインタはメモリアドレスです。ポインターは型付き(例int*:)または型なし(例:)のいずれかですvoid*。A Windowsハンドルは、通常のメモリアドレスと同じサイズ(または小さい)であり、(ファイルやウィンドウなど)は、システムリソースを表す値です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.