サーチ…


備考

ポインタとunsafe

その性質上、ポインタは検証不能なコードを生成します。したがって、ポインタ型を使用するには、 unsafeコンテキストが必要です。

System.IntPtr型は、 void*囲む安全なラッパーです。これは、安全ではないコンテキストが他のタスクを手作業で実行する必要がない場合、 void*より便利な代替として意図されています。

未定義の動作

CやC ++と同様に、ポインタの不正使用は未定義のビヘイビアを呼び出す可能性があり、メモリ破壊や意図しないコードの実行が副作用の可能性があります。ほとんどのポインタ操作の確認不可能な性質のため、ポインタの正しい使用法はプログラマの責任です。

ポインタをサポートする型

CやC ++とは異なり、すべてのC#型に対応するポインタ型があるわけではありません。以下の基準の両方が適用される場合、タイプTは対応するポインタタイプを有することができる。

  • Tは、struct型またはポインタ型です。
  • 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;
        }
    }
}

unsafeキーワードは、通常の方法でC#配列にアクセスするときに通常生成される境界チェックをポインタへのアクセスがunsafeために必要です。

fixedキーワードは、例外セーフな方法でオブジェクトを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ポインタとして使われます。サイズに依存しない性質のため、 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#では、2つのintポインタを宣言しています。

int* a, b; 

CおよびC ++では、次のスニペットは2つのintポインタを宣言しています。 C#では無効です:

int *a, *b;

void *

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