【问题标题】:What is the difference between IntPtr and Marshal.ReadIntPtr?IntPtr 和 Marshal.ReadIntPtr 有什么区别?
【发布时间】:2017-02-17 09:57:39
【问题描述】:

我确实想了解以下两者之间的区别:

new IntPtr(pointer.ToInt64() + 0x4);

Marshal.ReadIntPtr(pointer + 0x4);

他们给出了不同的结果,但做的事情不一样吗?

如果可能的话,你能否提供一个实际的例子来说明我对它的误解是什么?

【问题讨论】:

  • 没有。首先是将 4 添加到地址,因此 1000 + 4 = 1004。其次是指向 32 位数字(4 字节)的指针。因此,当您增加指针指针时,您一次移动 4 个字节,因此 1000 + (4 x 4 字节) = 1016。
  • IntPtr 常用于存储内存地址。这两个语句非常不同,第一个只是将地址增加 4。第二个也是这样做的,快速方式,and 读取内存。大概是为了检索一个指针值,一个存储在内存中的地址。

标签: c# marshalling intptr


【解决方案1】:

IntPtr 基本上是特定于平台的整数。它在 32 位操作系统中为 32 位,在 64 位操作系统中为 64 位。常用来表示指针,但也可以表示任意随机整数。

所以你的两种方法做不同的事情。首先(IntPtr 构造函数)只取您提供的任何数字并将其表示为IntPtr。在这种情况下,IntPtr 是否是有效的内存地址并不重要。

Marshal.ReadIntPtr 正在做不同的事情:它将您传递给它的任何内容视为内存地址,然后转到该地址,从那里读取 4 或 8 个字节,并返回代表该数据的 IntPtr

试试这个来验证:

IntPtr pointer = IntPtr.Zero;
var anotherPointer = new IntPtr(pointer.ToInt64() + 0x4);
var yetAnother = Marshal.ReadIntPtr(pointer + 0x4);

这将在第三行抛出内存访问冲突异常,因为您通常无法读取如此低地址(0x4)的内存。然而,第二行只是将您在此处传递的任何内容 (4) 返回为 IntPtr

【讨论】:

  • 您好 Evk,感谢您提供详细的答案,所以基本上您是在告诉我 ReadIntPtr 会像 new IntPtr(new IntPtr(...).ToInt64) 跳过验证一样,或者这是一个错误的假设?我的意思是从他们的描述来看是平等的。假设为了理智,我们使用 32 位。
  • 不,ReadIntPtr 将从您提供的内存位置读取整数值。因此,例如,您在那里提供 0x333333 。它转到内存位置 0x333333 并从那里读取整数。它可以是任何整数。 IntPtr 构造函数不会从内存中读取任何内容。这两种方法是完全不同的,完全没有关系。
  • 我明白了,我假设 IntPtr 也读过它,谢谢你的回复。在效率和不使用不安全的情况下,Marhsal.ReadIntPtr 是最快的还是唯一可用的选项,还是有其他选项?如果你不介意回复,以防你知道。
  • 如果您需要从指针中读取整数值,您可以使用非托管指针 (int*),使用 Marshal.ReadInt16(或 32 或 64)(如果您知道该整数的大小)或使用Marshal.ReadIntPtr(如果您出于某种原因需要特定于平台的整数)。没有其他我知道的选项。
猜你喜欢
  • 2012-10-21
  • 2010-10-02
  • 2011-12-12
  • 2010-09-16
  • 2012-03-14
  • 2012-02-06
  • 2011-02-25
  • 2011-11-22
  • 2015-03-26
相关资源
最近更新 更多