連載

C#入門

第21回 ポインタを使用できるunsafe

(株)ピーデー
川俣 晶
2002/02/16


ポインタを演算する

 ポインタに使用できるのは“++”や“--”演算子だけではない。四則演算や“==”などの比較演算子も使用できる。以下はポインタの引き算を、データ型を変えながら実行してみたサンプル・ソースである。

 1: using System;
 2:
 3: namespace ConsoleApplication9
 4: {
 5:   class Class1
 6:   {
 7:     unsafe static void test()
 8:     {
 9:       int [] array = { 1,2,3,4 };
10:       fixed( int * p1 = &array[0] )
11:       {
12:         fixed( int * p2 = &array[3] )
13:         {
14:           Console.WriteLine( p2-p1 );
15:
16:           short * p3 = (short *)p1;
17:           short * p4 = (short *)p2;
18:           Console.WriteLine( p4-p3 );
19:
20:           sbyte * p5 = (sbyte *)p1;
21:           sbyte * p6 = (sbyte *)p2;
22:           Console.WriteLine( p6-p5 );
23:         }
24:       }
25:     }
26:     static void Main(string[] args)
27:     {
28:       test();
29:     }
30:   }
31: }
ポインタの演算を行っているサンプル・プログラム7
配列の先頭と末尾へのポインタ間で、データ型を変えながら引き算を行っている。

 これを実行すると以下のようになる。

サンプル・プログラム7の実行結果
ポインタのサイズにより引き算の結果は異なってくる。

 14行目では、int型のポインタとして引き算をしている。18行目ではまったく同じ値を、データ型だけshortへのポインタに変換したうえで計算している。22行目では同様にsbyte型で行っている。結果は見てのとおりで、ポインタのサイズを意識して、結果が異なっていることが分かるだろう。つまり、p1とp2の間には、int型なら3個分、short型なら6個分、sbyte型なら12個分のすき間があるということが示されているわけである。

一時変数を容易に確保するstackalloc

 量の多いデータを扱う場合は配列を利用するのが1つの定石だが、配列は移動型であるため、ポインタ・アクセスが面倒になる。そこで、スタック上に配列のようなサイズの大きなデータを確保できれば扱いやすい。そのために、C#ではstackallocというキーワードが用意されている。これはC言語のalloca関数のようなものといえる。以下はそれを使用した例である。

 1: using System;
 2:
 3: namespace ConsoleApplication11
 4: {
 5:   class Class1
 6:   {
 7:     static void Main(string[] args)
 8:     {
 9:       unsafe
10:       {
11:         int * buffer = stackalloc int[4];
12:         for( int i=0; i<4; i++ )
13:         {
14:           *(buffer + i) = i;
15:         }
16:         for( int i=0; i<4; i++ )
17:         {
18:           Console.WriteLine( buffer[i] );
19:         }
20:       }
21:     }
22:   }
23: }
stackallocキーワードを使用したサンプル・プログラム8
通常、配列は移動型であるが、stackallocキーワードを付けることによってスタック上に割り当てることができる。

 これを実行すると以下のようになる。

サンプル・プログラム8の実行結果
ポインタにより順番に配列へ値を代入し、それを表示している。

 このように、配列でありながらfixedステートメントなしで処理できることが分かると思う。なお、ここでは2つ確認しておきたいことがある。第1は14行目である。このようなポインタを用いた式を使って配列にアクセスすることは、もちろん可能である。第2は、9〜20行目のunsafeブロックである。unsafeキーワードはメソッドなどに付けるだけでなく、ブロックを構成する使い方もできる。もし、メソッドの一部だけでunsafeコードを使用する場合は、このようなunsafeブロックを使った方が安全だろう。

 なお、stackallocしたメモリは、そのブロックを抜けると解放されてしまう。あくまでローカルな存在であることに注意が必要だ。stackallocしたメモリへの参照を戻り値として返すような使い方はできない。


 INDEX
  第21回 ポインタを使用できるunsafe
    1.unsafeコードとは何か
    2.固定型と移動型
    3.配列にポインタ・アクセスする
  4.ポインタを演算する
    5.本当にunsafeコードが欲しくなる事
 
「C#入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間