C#内存地址和变量

时间:2009-02-26 02:01:36

标签: c# .net memory-management

在C#中,有没有办法

  1. 获取存储在a中的内存地址 引用类型变量?
  2. 获取a的内存地址 变量?
  3. 编辑:

    int i;
    int* pi = &i;
    
    • 如何打印出pi的十六进制值?

3 个答案:

答案 0 :(得分:14)

对于#2,&运算符将以与C中相同的方式工作。如果变量不在堆栈中,则可能需要使用fixed语句将其固定为你工作,所以垃圾收集器不会移动它。

对于#1,引用类型比较棘手:您需要使用GCHandle,并且引用类型必须是blittable,即具有已定义的内存布局并且可按位进行复制。

为了以数字形式访问地址,您可以从指针类型转换为IntPtr(定义为与指针大小相同的整数类型),并从那里转换为uintulong(取决于底层机器的指针大小)。

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();
    }
}

答案 1 :(得分:5)

数字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关键字将该对象固定在内存中,以便它没有被垃圾收集器移动。

答案 2 :(得分:3)

最正确地回答你的问题:

#1是可能的,但有点棘手,应该只是出于调试原因:

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

这适用于任何对象,并实际返回内存中对象的内部指针。请记住,地址可以随时更改,因为GC喜欢在内存中移动对象。

#2指针不是对象,因此不会从它们继承 ToString 。您必须像以下那样将指针强制转换为 IntPtr

Console.WriteLine((IntPtr)pi);