【发布时间】:2010-10-09 23:36:15
【问题描述】:
在C#中,有没有办法
- 获取存储在 a 中的内存地址 引用类型变量?
- 获取内存地址 变量?
编辑:
int i;
int* pi = &i;
- 如何打印出 pi 的十六进制值?
【问题讨论】:
标签: c# .net memory-management
在C#中,有没有办法
编辑:
int i;
int* pi = &i;
【问题讨论】:
标签: c# .net memory-management
对于#2,& 运算符的工作方式与 C 中的相同。如果变量不在堆栈上,您可能需要在工作时使用fixed 语句将其固定,以便不过垃圾收集器不会移动它。
对于#1,引用类型更复杂:您需要使用GCHandle,并且引用类型必须是可位点的,即具有已定义的内存布局并且可以按位复制。
为了将地址作为数字访问,您可以从指针类型转换为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();
}
}
【讨论】:
int* 转换为IntPtr 允许它。
数字 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 关键字将该对象固定在内存中,这样它就不会由垃圾收集器移动。
【讨论】:
GCHandle.ToIntPtr 返回句柄本身的内部表示,而不是它指向的对象的地址。如果为同一个对象创建多个句柄,GCHandle.ToIntPtr 将为每个句柄返回不同的结果。 GCHandle.AddrOfPinnedObject 返回句柄指向的对象的地址。详情请见GCHandle.ToIntPtr vs. GCHandle.AddrOfPinnedObject。
最正确地回答您的问题:
#1 是可能的,但有点棘手,应该仅出于调试原因进行:
object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);
这适用于任何对象,并且实际上返回指向内存中对象的内部指针。请记住,由于 GC 喜欢在内存中移动对象,因此地址可以随时更改。
#2 指针不是对象,因此不会从它们继承 ToString。您必须像这样将指针转换为 IntPtr:
Console.WriteLine((IntPtr)pi);
【讨论】: