到底什么是IntPtr?


171

通过使用IntelliSense并查看其他人的代码,我遇到了这种IntPtr类型。每次需要使用它时,我都会简单地放置null或,IntPtr.Zero并发现大多数功能都可以使用。究竟是什么?何时/为什么使用?

Answers:


158

这是“本地(特定于平台)的大小整数”。它在内部表示为,void*但作为整数公开。您可以在需要存储非托管指针并且不想使用unsafe代码的任何时候使用它。IntPtr.Zero有效NULL(空指针)。


53
指针是指向内存中地址的东西。在托管语言中,您具有引用(地址可以移动),在非托管语言中,您具有指针(地址是固定的)
Colin Mackay 2009年

93
通常(跨编程语言),指针是代表内存中物理位置的数字。一个指针是(几乎总是)一个点为0,被广泛认为是“不指向任何东西”。由于系统具有不同数量的受支持内存,因此并不总是需要相同数量的字节来保存该数字,因此我们将“本地大小整数”称为一个可以在任何特定系统上保存指针的字节。
山姆·哈威尔2009年

5
对该评论@ 280Z28 +1,这是我所见过的最简洁的指针解释。
BlueRaja-Danny Pflughoeft 2010年

9
之所以称为IntPtr,是因为要从不受管理的本机代码C / C ++中使用它,您将必须使用类比类型:intptr_t。C#的IntPtr完全映射到C / C ++的intptr_t。它可能实现为intptr_t。在C / C ++中,保证intptr_t类型的大小与void *类型的大小相同。
ПетърПетров

2
@Trap“一种特定于平台的类型,用于表示指针或句柄。” 不是“特定于平台的整数”,而是“表示指针或句柄的特定于平台的方式”。IntPtr非常合理,因为它是一个整数(如数学整数)和一个指针(如指针)。该Int部分与int类型无关-它是一个概念,而不是特定类型。公平地说,CLI规范唯一说的是它确实是“整数,本机大小”。哦,好吧:)
六安'09

69

它是一个足够大的值类型,可以存储本地或不安全代码中使用的内存地址,但不能直接用作安全托管代码中的内存地址。

您可以使用它IntPtr.Size来确定您是在32位还是64位进程中运行,因为它将分别为4字节或8字节。


16
关于检测该进程的地址空间大小的要点。
Noldorin

@Noldorin是的,但不一定可靠。过去,有很多具有多种指针类型的体系结构,并且在Windows上,IntPtr无论体系结构如何,它们也用于表示32位句柄(尽管Size在这种情况下仍为8)。CLI规范仅指出它是“本机大小”的整数,但实际上并没有说太多。
六安2013年

@Luaan并没有真正改变我的答案,对吗?所谓IntPtr(在整个CLR源代码中使用)是一个足够大的值,可以保存一个内存地址。当然,它可以保留较小的值。某些体系结构具有多种指针类型,但必须具有最大的指针类型。
Daniel Earwicker

@DanielEarwicker好吧,据我所知,当前的任何.NET实现都不是问题。但是,(历史性)问题不仅与大小有关,而且各种指针可能完全不兼容。在一个接近今天的示例中,即使“本机指针大小”仍为32位,PAE仍将使用64位地址。一直追溯到“ '32位系统'到底意味着什么”这一论点。现在我们有256位和512位数字寄存器,但仍将其称为64位。即使您实际上无法使用64位“指针”寻址64位物理内存。一团糟。
六安'09

1
其中有些比较复杂,但是IntPtr仍然是“足以存储内存地址的值类型”。举一个例子,它没有最大的硬件寄存器那么大。那不是它的目的。它足够大以表示一个内存地址。然后是这样的东西:stackoverflow.com/questions/12006854/…其中,“指针”一词用于除内存地址以外的其他内容-这就是为什么我专门说“内存地址”。
Daniel Earwicker

48

这是一个例子:

我正在编写一个与高速相机接口的C#程序。相机具有自己的驱动程序,可自动获取图像并将其加载到计算机的内存中。

因此,当我准备将最新的图像引入程序中时,相机驱动程序会为我提供一个IntPtr,以将图像已存储在物理内存中的位置,因此我不必浪费时间/资源来创建另一个图像内存块以存储已在内存中的图像。IntPtr只是告诉我图像已经在哪里。


7
那么IntPtr简单允许您在托管代码中使用非托管指针(如相机驱动程序中使用的指针)吗?
卡伦·罗杰斯

5
是。很好,在这种情况下,相机驱动程序很可能在幕后使用了非托管驱动程序,但是为了在“仅限托管”环境中正常运行,它提供了IntPtr来允许我安全地处理数据。
bufferz

3
那么,为什么不只返回流(字节数组)呢?为什么不安全或无法返回值?
松饼人

35

直接解释

一个IntPtr的是一个整数,其是大小相同的指针

您可以使用IntPtr将指针值存储为非指针类型。此功能在.NET中非常重要,因为使用指针很容易出错,因此在大多数情况下是非法的。通过允许将指针值存储在“安全”数据类型中,可以在更安全的高级代码中甚至在不直接支持指针的.NET语言中实现不安全代码段之间的连接。

IntPtr的大小是特定于平台的,但是由于系统会自动使用正确的大小,因此很少需要考虑此细节。

名称“ IntPtr”令人困惑- Handle可能更合适。我最初的猜测是,“IntPtr的”是一个指针一个整数。有关IntPtrMSDN文档,在没有提供有关名称含义的深入了解的情况下,它的细节有些神秘。

另一种观点

An IntPtr是一个有两个限制的指针:

  1. 不能直接取消引用
  2. 它不知道它指向的数据类型。

换句话说,an IntPtr就像void*- 一样,但具有可以(但不应)用于基本指针算术的额外功能。

为了取消对an的引用IntPtr,您可以将其强制转换为真正的指针(该操作只能在“不安全”的上下文中执行),也可以将其传递给该类提供的帮助程序InteropServices.Marshal。使用Marshal类会给人一种安全的假象,因为它不需要您处于显式的“不安全”上下文中。但是,它不能消除使用指针所固有的崩溃风险。


2
“ C”编程语言的C99标准中有一个名称“ intptr”的先例。linux.die.net/man/3/intptr_t
布伦特·布拉德本

17

什么是指针?

在所有语言中,指针都是存储内存地址的一种变量,您可以要求它们告诉您所指向的地址或所指向地址

可以将指针视为某种书签。除了使用指针而不是用来快速跳转到书中的页面之外,使用指针来跟踪或映射内存块。

想象一下程序的内存就像一个65535字节的大数组。

指针听话指向

指针每个记住一个内存地址,因此它们每个都指向内存中的一个地址。

作为一个整体,指针会记住并重新调用内存地址,并遵守您的每条命令。

你是他们的国王。

C#中的指针

特别是在C#中,指针是一个整数变量,用于存储0到65534之间的内存地址。

同样针对C#的指针是int类型的,因此是有符号的。

但是,您不能使用负编号的地址,也不能访问65534以上的地址。任何尝试这样做都会抛出System.AccessViolationException。

像这样声明一个称为MyPointer的指针:

int * MyPointer;

C#中的指针是一个int,但是C#中的内存地址从0开始,一直扩展到65534。

尖锐的东西应格外小心

不安全一词旨在吓intended您,原因很充分:指针是尖的东西,尖的东西,例如剑,斧头,指针等,应格外小心。

指针使程序员可以严格控制系统。因此,犯错误可能会造成更严重的后果。

为了使用指针,必须在程序的属性中启用不安全的代码,并且必须仅在标记为不安全的方法或块中使用指针。

不安全块的示例

unsafe
{
    // Place code carefully and responsibly here.

}

如何使用指针

声明或实例化变量或对象后,它们将存储在内存中。

  • 通过使用*符号前缀声明指针。

int *MyPointer;

  • 要获取变量的地址,请使用&符号前缀。

MyPointer = &MyVariable;

将地址分配给指针后,将适用以下条件:

  • 如果不带*前缀,则指向指向int的内存地址。

MyPointer = &MyVariable; // Set MyPointer to point at MyVariable

  • 使用*前缀可以获取存储在所指向的内存地址中的值。

"MyPointer is pointing at " + *MyPointer;

由于指针是保存内存地址的变量,因此可以将该内存地址存储在指针变量中。

认真负责地使用指针的示例

    public unsafe void PointerTest()
    {
        int x = 100; // Create a variable named x

        int *MyPointer = &x; // Store the address of variable named x into the pointer named MyPointer

        textBox1.Text = ((int)MyPointer).ToString(); // Displays the memory address stored in pointer named MyPointer

        textBox2.Text = (*MyPointer).ToString(); // Displays the value of the variable named x via the pointer named MyPointer.

    }

注意,指针的类型是int。这是因为C#将内存地址解释为整数(int)。

为什么用int代替uint?

没有充分的理由。

为什么要使用指针?

指针很有趣。由于大量的计算机由内存控制,因此指针使程序员可以更好地控制程序的内存。

内存监视。

使用指针读取内存块并监视所指向的值如何随时间变化。

负责任地更改这些值,并跟踪更改对计算机的影响。


2
65534指针范围似乎非常错误。您应该提供参考。
布伦特·布拉德本'18

1
我投了赞成票,因为这是一篇很棒的文章,解释了指针。我希望看到对您提到的规格的一些引用(如上所述)。然而; 这个答案与问题无关。问题是关于System.IntPtr。我想在末尾看到更新的答案,还请解释什么System.IntPtr以及它与C#中不安全指针的关系。
Michael Puckett II

7

MSDN告诉我们:

IntPtr类型设计为整数,其大小是特定于平台的。也就是说,这种类型的实例在32位硬件和操作系统上应该是32位,在64位硬件和操作系统上应该是64位。

IntPtr类型可由支持指针的语言使用,并作为在支持和不支持指针的语言之间引用数据的常用方式。

IntPtr对象也可以用于保存句柄。例如,在System.IO.FileStream类中广泛使用IntPtr的实例来保存文件句柄。

IntPtr类型兼容CLS,而UIntPtr类型不兼容。公共语言运行时中仅使用IntPtr类型。提供UIntPtr类型主要是为了保持与IntPtr类型的体系结构对称性。

http://msdn.microsoft.com/zh-CN/library/system.intptr(VS.71).aspx


5

嗯,这是MSDN页面是涉及IntPtr

第一行显示:

特定于平台的类型,用于表示指针或句柄。

关于页面的指针或句柄是什么状态:

IntPtr类型可由支持指针的语言使用,并作为在支持和不支持指针的语言之间引用数据的常用方式。

IntPtr对象也可以用于保存句柄。例如,在System.IO.FileStream类中广泛使用IntPtr的实例来保存文件句柄。

指针是对包含您感兴趣的某些数据的内存区域的引用。

句柄可以是对象的标识符,并且当双方都需要访问该对象时,该句柄在方法/类之间传递。


2

An IntPtr是一种值类型,主要用于保存内存地址或句柄。甲指针是一个存储器地址。可以键入(例如int*)或不键入(例如)指针void*。甲视窗手柄是通常具有相同的尺寸(或小于)的存储器地址和表示系统资源(如文件或窗口)的值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.