読者です 読者をやめる 読者になる 読者になる

C#のfixedステートメントの使い方

C#

概要
1. fixedを使用しなくても、unsafeメソッド内で使用可能なポインタ
2. unsafeメソッド内で使用不可能なポインタ
3. unsafeメソッド内でfixedステートメント併用で使用可能になるもの

1.fixedを使用しなくても、unsafeメソッド内で使用可能なポインタ

・ローカル変数へのポインタ

int i = 123;
int *p1 = &i;

・ローカル構造体へのポインタ

SampleStruct sampleStruct;
sampleStruct.x = 123;
SampleStruct *p3 = &sampleStruct;

変数・構造体どちらの場合も、ローカルポインタへローカル変数・構造体へのポインタを代入しています。

これは

・実体がスタック上にある
・ポインタ変数もスタック上にある

ことで、ポインタが存在している間、
「実体がガベージコレクタによる影響を受けず、常に存在していることが保障される」
という意味で、コンパイル上問題ありません。

上のケースは、fixedステートメント無しで常にコンパイル可能です。

2.unsafeメソッド内で使用不可能なポインタ

・ヒープクラスインスタンスへのポインタ

SampleClass sampleClass = new SampleClass();
SampleClass *p2 = &sampleClass;

・ボックス化した構造体へのポインタ

SampleStruct sampleStruct;
object sampleStruct2 = (object)sampleStruct;
SampleStruct *p4 = &(SampleStruct)sampleStruct2;

上の2つは、「実体がガベージコレクタによりいつ無効になるか分からない」
という意味でコンパイル出来ません。
無効になるというのは、削除されるか再配置によりアドレスが変更されてしまう事を意味します。

しかしfixedステートメントを使う事で、限定的にポインタを得る事は可能です。

3.unsafeメソッド内でfixedステートメント併用で使用可能になるもの

・クラスメンバへのポインタ

SampleClass sampleClass = new SampleClass();
fixed(int *p3 = &sampleClass.x)
{
    Console.WriteLine(*p3);
}

上記、fixedステートメントでクラスメンバxへのポインタp3を取得しています。
これはfixedブロック内だけで有効になり、そのブロック中は参照が保障されます。
ただし、クラスそのものへの参照や、複雑なキャストを含んだポインタは使用できない様です。

・配列への先頭ポインタ

byte[] fileImage = new byte[inputFile.Length];
fixed(byte *basePtr = &fileImage[0])
{
    // ポインタを使った処理
}

配列への先頭アドレスをポインタに代入しています。
この時、fixedを使用すれば、配列がガベージコレクタによる影響を受けることを避けられます。

以上になります。

参考:
連載 改訂版 C#入門:第21章 ポインタを使用できる「安全でないコード」 (1/4) - @IT