C#内存地址和变量
Posted
技术标签:
【中文标题】C#内存地址和变量【英文标题】:C# memory address and variable 【发布时间】:2010-10-09 23:36:15 【问题描述】:在C#中,有没有办法
-
获取存储在 a 中的内存地址
引用类型变量?
获取内存地址
变量?
编辑:
int i;
int* pi = &i;
如何打印出 pi 的十六进制值?
【问题讨论】:
【参考方案1】:对于#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();
【讨论】:
#2,这很酷。但是如何将内存地址作为字符串获取。说int i; int* pi = &i;我无法使用 Console.WriteLine(pi); 打印它我希望打印 0x0439ecc4 之类的内容。有什么线索吗? Console.WriteLine("0x" + pi.ToString("x") 将打印十六进制值 @Hamish, pi.ToString("x") 引发编译错误。 “操作员 '。'不能应用于“int*”类型的操作数” 您需要使用“->”运算符。 pi->ToString() @rism,OP 希望将指针的值重新解释为整数,而不是指针指向的值。将int*
转换为IntPtr
允许它。【参考方案2】:
数字 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
关键字将该对象固定在内存中,这样它就不会由垃圾收集器移动。
【讨论】:
很奇怪,为什么代码不能用 string str = "hello" 编译;字符串* ptr = str; ?有什么想法吗? 我的错,这实际上根本不可能。你不能有一个指向托管对象的指针,你必须使用一个 IntPtr。 为什么投反对票?如果你不说你不喜欢什么,那是毫无意义的......GCHandle.ToIntPtr
返回句柄本身的内部表示,而不是它指向的对象的地址。如果为同一个对象创建多个句柄,GCHandle.ToIntPtr
将为每个句柄返回不同的结果。 GCHandle.AddrOfPinnedObject
返回句柄指向的对象的地址。详情请见GCHandle.ToIntPtr vs. GCHandle.AddrOfPinnedObject。【参考方案3】:
最正确地回答您的问题:
#1 是可能的,但有点棘手,应该仅出于调试原因进行:
object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);
这适用于任何对象,并且实际上返回指向内存中对象的内部指针。请记住,由于 GC 喜欢在内存中移动对象,因此地址可以随时更改。
#2 指针不是对象,因此不会从它们继承 ToString。您必须像这样将指针转换为 IntPtr:
Console.WriteLine((IntPtr)pi);
【讨论】:
以上是关于C#内存地址和变量的主要内容,如果未能解决你的问题,请参考以下文章