【问题标题】:Just what is an IntPtr exactly?究竟什么是 IntPtr?
【发布时间】:2010-11-12 00:01:51
【问题描述】:

通过使用IntelliSense并查看其他人的代码,我遇到了这个IntPtr类型;每次需要使用它时,我只需输入nullIntPtr.Zero 并发现大多数功能都可以使用。它到底是什么以及何时/为什么使用它?

【问题讨论】:

    标签: c# intptr


    【解决方案1】:

    这是一个“本机(特定于平台)大小的整数”。它在内部表示为void*,但显示为整数。您可以在需要存储非托管指针并且不想使用unsafe 代码时使用它。 IntPtr.Zero 实际上是 NULL(一个空指针)。

    【讨论】:

    • 指针是指向内存地址的东西。在托管语言中,您有引用(地址可以移动),而在非托管语言中,您有指针(地址是固定的)
    • 通常(跨编程语言),指针是表示内存中物理位置的数字。 null 指针(几乎总是)指向 0,并且被广泛认为是“不指向任何东西”。由于系统支持的内存量不同,因此保存该数字并不总是需要相同数量的字节,因此我们将其称为“本机大小整数”,它可以保存任何特定系统上的指针。
    • +1 评论@280Z28,这是我见过的最简洁的指针解释。
    • 它被称为 IntPtr,因为要在非托管本机代码 C/C++ 中使用它,您必须使用类比类型:intptr_t。 C# 的 IntPtr 精确映射到 C/C++ 的 intptr_t。它可能被实现为 intptr_t。在 C/C++ 中,intptr_t 类型保证与 void* 类型大小相同。
    • @Trap "一种特定于平台的类型,用于表示指针或句柄。"不是“特定于平台的整数”,而是“表示指针或句柄的特定于平台的方式”。 IntPtr 非常有意义,因为它是一个整数(如数学整数)和一个指针(如指针)。 Int 部分与 int 类型几乎没有关系——它是一个概念,而不是特定类型。虽然公平地说,CLI 规范唯一说的是它确实是一个“整数,原生大小”。哦,好吧:)
    【解决方案2】:

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

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

    【讨论】:

    • 关于检测进程地址空间大小的要点。
    • @Noldorin 是的,但不一定可靠。过去,有很多架构具有多种指针类型,在 Windows 上,IntPtr 也用于表示与架构无关的 32 位句柄(尽管 Size 在这种情况下仍然表示 8)。 CLI 规范只指出它是一个“本机大小”的整数,但这并没有说太多,真的。
    • @Luaan 并没有真正改变我的答案,对吗? IntPtr 被称为(并在整个 CLR 源代码中使用)作为一个足够大的值来保存内存地址。当然,它可以保持较小的值。有些架构有多种指针类型,但必须有一个是集合中最大的。
    • @DanielEarwicker 好吧,据我所知,当前的任何 .NET 实现都不是问题。但是,(历史)问题不仅仅是大小 - 各种指针可能完全不兼容。在更接近今天的示例中,PAE 将使用 64 位地址,即使“本机指针大小”仍然是 32 位。它一直回到争论“'32 位系统'是什么意思,真的吗?”我们现在有 256 位和 512 位数字寄存器,但仍称其为 64 位。即使您无法使用 64 位“指针”实际寻址 64 位物理内存。真是一团糟。
    • 有些复杂,但 IntPtr 仍然是“一个足够大的值类型来存储内存地址”。举一个例子,它没有最大的硬件寄存器那么大。那不是它的用途。它足够大,可以代表一个内存地址。然后是这样的东西:stackoverflow.com/questions/12006854/… 我们有“指针”这个词被用于内存地址以外的东西——这就是为什么我特别说“内存地址”。
    【解决方案3】:

    这是一个例子:

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

    因此,当我准备好将最新图像带入我的程序以使用时,相机驱动程序为我提供了一个 IntPtr,该图像已存储在物理内存中,因此我不必浪费时间/资源创建另一个内存块来存储已经在内存中的图像。 IntPtr 只是显示图像已经在哪里。

    【讨论】:

    • 所以 IntPtr simple 允许您在托管代码中使用非托管指针(就像在您的相机驱动程序中使用的那样)?
    • 是的。那么在这种情况下,相机驱动程序很可能在后台使用非托管驱动程序,但为了在仅限托管的世界中正常运行,它提供了 IntPtr 以允许我安全地处理数据。
    • 那么它为什么不给你一个流(字节数组)呢?为什么不安全或无法返回值?
    【解决方案4】:

    直接解释

    IntPtr 是一个 整数,与 指针 大小相同。

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

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

    “IntPtr”这个名字令人困惑——像Handle 这样的名字可能更合适。我最初的猜测是“IntPtr”是一个指针一个整数。 MSDN documentation of IntPtr 涉及到一些神秘的细节,却没有提供太多关于名称含义的见解。

    另一种视角

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

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

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

    为了取消对IntPtr 的引用,您可以将其转换为真正的指针(只能在“不安全”上下文中执行的操作),也可以将其传递给辅助例程,例如由InteropServices.Marshal 班级。使用Marshal 类会产生安全的错觉,因为它不需要您处于明确的“不安全”上下文中。但是,它并没有消除使用指针固有的崩溃风险。

    【讨论】:

    【解决方案5】:

    什么是指针?

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

    指针可以被认为是一种书签。除了用于快速跳转到书中的一页之外,指针用于跟踪或映射内存块。

    将您的程序的内存想象成一个 65535 字节的大数组。

    指针乖乖指向

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

    作为一个组,指针会记住和回忆内存地址,服从你的每一个命令,令人作呕。

    你是他们的国王。

    C# 中的指针

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

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

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

    一个名为 MyPointer 的指针声明如下:

    int *MyPointer;

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

    要特别小心处理尖锐的事情

    不安全这个词旨在吓唬你,并且有一个很好的理由:指针是尖锐的东西,并且尖锐的东西例如剑、斧头、指针等应特别小心处理。

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

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

    不安全块示例

    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?

    没有充分的理由。

    为什么要使用指针?

    指针很有趣。由于计算机的大部分内容由内存控制,因此指针使程序员能够更好地控制其程序的内存。

    内存监控。

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

    负责任地更改这些值并跟踪您的更改如何影响您的计算机。

    【讨论】:

    • 65534 作为指针范围似乎非常错误。您应该提供参考。
    • 我投了赞成票,因为这是一篇解释指针的好文章。我希望看到对您提到的规格的一些参考(如上所述)。然而;这个答案与问题无关。问题是关于System.IntPtr。我希望看到最后更新的答案,解释System.IntPtr 以及它与 C# 中不安全指针的关系。
    【解决方案6】:

    MSDN 告诉我们:

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

    IntPtr 类型可以被 支持指针的语言,以及 作为引用数据的常用手段 在做和不做的语言之间 支持指针。

    IntPtr 对象也可用于 握住把手。例如,实例 IntPtr 被广泛用于 System.IO.FileStream 类持有 文件句柄。

    IntPtr 类型符合 CLS, 而 UIntPtr 类型不是。仅有的 IntPtr 类型用于常见的 语言运行时。 UIntPtr 类型是 主要用于维护 与 IntPtr 的架构对称 输入。

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

    【讨论】:

      【解决方案7】:

      这是处理IntPtrMSDN page

      第一行写着:

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

      至于页面继续状态的指针或句柄是什么:

      IntPtr 类型可以被 支持指针的语言,以及 作为引用数据的常用手段 在做和不做的语言之间 支持指针。

      IntPtr 对象也可用于 握住把手。例如,实例 IntPtr 被广泛用于 System.IO.FileStream 类持有 文件句柄。

      指针是对存储您感兴趣的一些数据的内存区域的引用。

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

      【讨论】:

        【解决方案8】:

        IntPtrvalue type,主要用于保存内存地址或句柄。 pointer 是一个内存地址。指针可以有类型(例如int*)或无类型(例如void*)。 Windows handle 是一个通常与内存地址大小相同(或更小)的值,表示系统资源(如文件或窗口)。

        【讨论】:

          猜你喜欢
          • 2014-10-28
          • 2012-08-27
          • 2011-03-18
          • 2011-01-22
          • 1970-01-01
          相关资源
          最近更新 更多