C# アンセーフ コード完全ガイド:ポインタとメモリ管理の実践
C# では、unsafe 修飾子でマークされた関数またはコード ブロック内でポインタ変数を使用できます。アンセーフ コードまたはアンマネージ コードとは、ポインタ変数を使用するコード ブロックのことです。
ポインタ
ポインタとは、別の変数のアドレス、つまりメモリ位置の直接アドレスを値として持つ変数です。通常の変数や定数と同様に、ポインタを使用して変数のアドレスを格納する前に、ポインタを宣言する必要があります。
ポインタ宣言の一般的な形式は次のとおりです。
型 *変数名;
有効なポインタ宣言の例:
int *ip; // 整数へのポインタ double *dp; // double へのポインタ float *fp; // float へのポインタ char *ch; // 文字へのポインタ
次の例は、unsafe 修飾子を使用して C# でポインタを使用する方法を示しています。
using System;
namespace UnsafeCodeApplication {
class Program {
static unsafe void Main(string[] args) {
int var = 20;
int* p = &var;
Console.WriteLine("Data is: {0} ", var);
Console.WriteLine("Address is: {0}", (int)p);
Console.ReadKey();
}
}
}
上記のコードをコンパイルして実行すると、次のような結果が得られます。
Data is: 20 Address is: 99215364
メソッド全体を unsafe にする代わりに、コードの一部分だけを unsafe として宣言することもできます。次のセクションの例でこれを示します。
ポインタを使用したデータ値の取得
ポインタ変数が参照する位置に格納されているデータを、ToString() メソッドを使って取得できます。次の例でこれを示します。
using System;
namespace UnsafeCodeApplication {
class Program {
public static void Main() {
unsafe {
int var = 20;
int* p = &var;
Console.WriteLine("Data is: {0} ", var);
Console.WriteLine("Data is: {0} ", p->ToString());
Console.WriteLine("Address is: {0} ", (int)p);
}
Console.ReadKey();
}
}
}
上記のコードをコンパイルして実行すると、次の結果が得られます。
Data is: 20 Data is: 20 Address is: 77128984
ポインタをメソッド パラメータとして渡す
ポインタ変数をメソッドのパラメータとして渡すことができます。次の例でこれを説明します。
using System;
namespace UnsafeCodeApplication {
class TestPointer {
public unsafe void swap(int* p, int* q) {
int temp = *p;
*p = *q;
*q = temp;
}
public unsafe static void Main() {
TestPointer p = new TestPointer();
int var1 = 10;
int var2 = 20;
int* x = &var1;
int* y = &var2;
Console.WriteLine("Before Swap: var1:{0}, var2: {1}", var1, var2);
p.swap(x, y);
Console.WriteLine("After Swap: var1:{0}, var2: {1}", var1, var2);
Console.ReadKey();
}
}
}
上記のコードをコンパイルして実行すると、次の結果が得られます。
Before Swap: var1: 10, var2: 20 After Swap: var1: 20, var2: 10
ポインタを使用した配列要素へのアクセス
C# では、配列名と、配列のデータと同じデータ型へのポインタは、同じ変数型ではありません。たとえば、int *p と int[] p は異なる型です。ポインタ変数 p はインクリメントできます(メモリ上で固定されていないため)が、配列のアドレスはメモリ上で固定されているため、インクリメントできません。
したがって、C や C++ のように(参考:C 言語のポインタ)ポインタ変数を使って配列データにアクセスする必要がある場合は、fixed キーワードを使ってポインタを固定する必要があります。
次の例でこれを示します。
using System;
namespace UnsafeCodeApplication {
class TestPointer {
public unsafe static void Main() {
int[] list = {10, 100, 200};
fixed(int* ptr = list) /* 配列のアドレスをポインタに取得 */
for (int i = 0; i < 3; i++) {
Console.WriteLine("Address of list[{0}]={1}", i, (int)(ptr + i));
Console.WriteLine("Value of list[{0}]={1}", i, *(ptr + i));
}
Console.ReadKey();
}
}
}
上記のコードをコンパイルして実行すると、次の結果が得られます。
Address of list[0] = 31627168 Value of list[0] = 10 Address of list[1] = 31627172 Value of list[1] = 100 Address of list[2] = 31627176 Value of list[2] = 200
アンセーフ コードのコンパイル
アンセーフ コードをコンパイルするには、コマンドライン コンパイラで /unsafe コマンドライン スイッチを指定する必要があります。
たとえば、アンセーフ コードを含む prog1.cs というプログラムをコマンドラインからコンパイルするには、次のコマンドを実行します。
csc /unsafe prog1.cs
Visual Studio IDE を使用している場合は、プロジェクトのプロパティでアンセーフ コードの使用を有効にする必要があります。
手順:
ソリューション エクスプローラーのプロパティ ノードをダブルクリックして プロジェクトのプロパティを開きます。
ビルド タブをクリックします。
「アンセーフ コードの許可」 オプションをオンにします。
C言語
- 抵抗器カラーコード完全ガイド:値、公差、Eシリーズ規格のデコード
- AC/DC回路の標準配線色コード:IEC、米国、英国、カナダ
- 包括的配線色コードガイド — 米国、ヨーロッパ、カナダなど
- データマトリックスとQRコードの選び方:あなたのビジネスに最適なのはどっち?
- Haas フライス盤 Mコード完全ガイド: 機能・設定・使用法
- Mach3 Mコード総合ガイド:CNC加工用
- Mコードマスター: CNCプログラミングクイズ
- Gコードマスター: CNCプログラミングクイズに挑戦
- C++ポインタをマスター:概念、例、実践的応用
- C 言語ポインタ完全ガイド: 型、使い方、ベストプラクティス
- C言語ポインタ完全マスター:実践的ステップで上級プログラミングへ