2010-07-28 87 views
2

在C++中,显示指向对象的指针的实际值非常简单。例如:显示对对象引用的值

void* p = new CSomething(); 
cout << p; 

有没有办法在.NET中做这样的事情?

这样做的价值只能是教育性的,例如,为了演示的目的,在显示一个值的学生看到,而不是仅仅比较参考平等或空(无)证明浅拷贝,不变性等。

回答

6

编译这个如果这是教育的目的,我建议您改用调试器。如果将SOS.dll(它是.NET框架的一部分)加载到WinDbg甚至Visual Studio中,则可以检查内存中的实际对象。

E.g.列出堆使用!dumpheap -stat命令。 !do命令在指定的内存地址上转储管理对象等等。 SOS有许多命令可以让你检查内部的.NET结构,所以它是一个非常有用的工具,用于了解更多关于运行时的信息。

通过使用此调试器,您不受限于查看演示应用程序。您可以查看实际应用程序的细节。此外,你会拿起一些真正有用的调试技巧。

有几个很好的介绍使用WinDbg + SOS进行调试。检查Tess' blog有很多教程。

0

我明白,如果你提供编译器/不安全选项,你将被允许编写'不安全'的代码,并有权访问指针。

我没有测试过这一点,但发现它in this artice

编辑:

记得好像最主要的是,你将不得不使用不安全的代码与unsafe关键字标记的任何代码:

unsafe public static void Main() 
+0

不安全的代码不会让您拥有指向托管类型的指针。请参阅[修复](http://msdn.microsoft.com/en-us/library/f58wzh21%28v=VS.71%29.aspx)文档。 – 2010-07-28 18:01:58

3

RuntimeHelpers.GetHashCode会给你一个基于身份的哈希码。实际上,这可能是基于地址。正如所解释的:

,你关心 对象的身份“RuntimeHelpers.GetHashCode是有用 在方案中两个字符串 相同的内容将返回 不同的值 RuntimeHelpers.GetHashCode,因为 它们是不同的字符串对象。 , 虽然他们的内容是相同的。“

实习字符串文字是主要的可能的例外。这在C++中实际上是一样的。

+0

我不确定你为什么会陷入低谷。当然你的答案是不同的,但这是思考的好去处。的确,Object.GetHashCode()(RuntimeHelpers使用的)是基于对象在内存中的位置,因为这是该级别对象的唯一独特方面。在调试过程中,我经常会调用Object.GetHashCode()来验证两个引用是否指向同一个对象。 – 2010-07-28 18:14:46

0

在.NET中,你根本不用指针。所以你会创建引用对象,你可以随时看到它的值。

比较参考对象时,比较参考,而不是实际值! (除了比较字符串,其中'=='被重载)。

也许你想证明将阐述什么事情的.NET示例...

-2
unsafe 
{ 
    object o = new Object(); 
    int *ptr = &o; //Get address 

    Console.WriteLine((int)ptr); //Write address 
} 

您需要用/不安全开关

+0

不起作用。它会给[CS0208](http://msdn.microsoft.com/en-us/library/x2estayf%28VS.80%29.aspx),“无法获取地址,获取大小或声明指针到托管类型('类型')“。 &运算符不能应用于托管类型。 – 2010-07-28 18:05:31

+0

我认为这需要:'fixed(int * ptr =&o){...}' – 2010-07-28 18:09:24

+0

@Tim,no。 '&o'在所有情况下都是无效的。 – 2010-07-28 18:14:36

7

您可以使用GCHandle来获取固定对象的地址。 GC可以移动物体,所以唯一明智的地址是固定物体。

GCHandle handle = GCHandle.Alloc(obj, GCHandleType.Pinned); 
Console.WriteLine(handle.AddrOfPinnedObject().ToInt32()); 
handle.Free(); 

请记住,GCHandle只会固定原始类型或blittable类型的对象。一些对象是blittable(你可以设置它为演示目的,所以它的工作原理),但任何引用类型不会blittable。

您需要使用[StructLayout(LayoutKind.Sequential)]添加明确的blittable描述,或者使用调试器直接检查不符合这些条件的对象的地址。

0

您可以在.NET中检索对象的地址,例如使用不安全的代码,但您获取的地址只是临时的 - 它将成为您接收地址的快照。

下一次垃圾收集情况,你的对象的地址可能会改变:

  • 如果对象不再从任何地方引用,它会被收集,以及其他一些对象将占用地址
  • 如果该对象仍在被引用,它可能会被提升到更高一代(因此被移动到不同的GC堆)。或者,如果它已经在第2代,它可能会因为堆压缩而移动到内存中。

垃圾收集器的存在是为什么int*指针在@的Jesper在一个{ }块的范围存在的原因。指针仅在该块内固定;一旦执行离开块,该对象有权被收集和/或移动。