web-dev-qa-db-ja.com

C#のメモリアドレスと変数

c#では、する方法はありますか

  1. 参照型変数に格納されているメモリアドレスを取得しますか?
  2. 変数のメモリアドレスを取得しますか?

編集:

int i;
int* pi = &i;
  • Piの16進数値をどのように出力しますか?
25
Ray Lu

#2の場合、&演算子はCと同じように機能します。変数がスタック上にない場合は、fixedステートメントを使用して、ガベージコレクターが移動しないように、作業中に変数を固定する必要がある場合があります。

#1の場合、参照タイプはよりトリッキーです。GCHandleを使用する必要があり、参照タイプはblittableである必要があります。つまり、メモリレイアウトが定義されていて、ビットごとにコピーできる必要があります。

数値としてアドレスにアクセスするには、ポインター型からIntPtr(ポインターと同じサイズになるように定義された整数型)にキャストし、そこからuintまたはulong(基礎となるマシンのポインターサイズに応じて)にキャストできます)。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
class Blittable
{
    int x;
}

class Program
{
    public static unsafe void Main()
    {
        int i;
        object o = new Blittable();
        int* ptr = &i;
        IntPtr addr = (IntPtr)ptr;

        Console.WriteLine(addr.ToString("x"));

        GCHandle h = GCHandle.Alloc(o, GCHandleType.Pinned);
        addr = h.AddrOfPinnedObject();
        Console.WriteLine(addr.ToString("x"));

        h.Free();
    }
}
14
Jeffrey Hantin

番号1はまったく不可能です。管理対象オブジェクトへのポインターを持つことはできません。ただし、IntPtr構造体を使用して、参照内のポインターのアドレスに関する情報を取得できます。

GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned);
IntPtr pointer = GCHandle.ToIntPtr(handle);
string pointerDisplay = pointer.ToString();
handle.Free();

番号2の場合、&演算子を使用します。

int* p = &myIntVariable;

もちろん、ポインタは安全でないブロックで実行する必要があり、プロジェクト設定で安全でないコードを許可する必要があります。変数がメソッド内のローカル変数である場合、それはスタックに割り当てられるため、すでに修正されていますが、変数がオブジェクトのメンバーである場合、fixedキーワードを使用してそのオブジェクトをメモリに固定する必要があります。ガベージコレクターによって移動されないこと。

5
Guffa

あなたの質問に最も正確に答えるには:

#1は可能ですが少しトリッキーであり、デバッグの理由でのみ実行する必要があります。

object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);

これはどのオブジェクトでも機能し、実際にはメモリ内のオブジェクトへの内部ポインタを返します。メモリを越えてオブジェクトを移動することを好むGCのために、アドレスはいつでも変更できることに注意してください。

#2ポインタはオブジェクトではないため、それらからToStringを継承しません。次のように、ポインタをIntPtrにキャストする必要があります。

Console.WriteLine((IntPtr)pi);