【发布时间】:2010-11-12 00:01:51
【问题描述】:
通过使用IntelliSense并查看其他人的代码,我遇到了这个IntPtr类型;每次需要使用它时,我只需输入null 或IntPtr.Zero 并发现大多数功能都可以使用。它到底是什么以及何时/为什么使用它?
【问题讨论】:
通过使用IntelliSense并查看其他人的代码,我遇到了这个IntPtr类型;每次需要使用它时,我只需输入null 或IntPtr.Zero 并发现大多数功能都可以使用。它到底是什么以及何时/为什么使用它?
【问题讨论】:
这是一个“本机(特定于平台)大小的整数”。它在内部表示为void*,但显示为整数。您可以在需要存储非托管指针并且不想使用unsafe 代码时使用它。 IntPtr.Zero 实际上是 NULL(一个空指针)。
【讨论】:
IntPtr 非常有意义,因为它是一个整数(如数学整数)和一个指针(如指针)。 Int 部分与 int 类型几乎没有关系——它是一个概念,而不是特定类型。虽然公平地说,CLI 规范唯一说的是它确实是一个“整数,原生大小”。哦,好吧:)
它是一种足够大的值类型,可以存储在本机或不安全代码中使用的内存地址,但不能直接用作安全托管代码中的内存地址。
您可以使用IntPtr.Size 来确定您是在 32 位还是 64 位进程中运行,因为它分别是 4 或 8 个字节。
【讨论】:
IntPtr 也用于表示与架构无关的 32 位句柄(尽管 Size 在这种情况下仍然表示 8)。 CLI 规范只指出它是一个“本机大小”的整数,但这并没有说太多,真的。
这是一个例子:
我正在编写一个与高速相机接口的 C# 程序。相机有自己的驱动程序,它可以自动为我获取图像并将它们加载到计算机的内存中。
因此,当我准备好将最新图像带入我的程序以使用时,相机驱动程序为我提供了一个 IntPtr,该图像已存储在物理内存中,因此我不必浪费时间/资源创建另一个内存块来存储已经在内存中的图像。 IntPtr 只是显示图像已经在哪里。
【讨论】:
IntPtr 是一个 整数,与 指针 大小相同。
您可以使用 IntPtr 将指针值存储为非指针类型。此功能在 .NET 中很重要,因为使用指针非常容易出错,因此在大多数情况下都是非法的。通过允许将指针值存储在“安全”数据类型中,unsafe 代码段之间的管道可以用更安全的高级代码实现——甚至可以用不安全的 .NET 语言来实现。直接支持指针。
IntPtr 的大小是特定于平台的,但很少需要考虑这个细节,因为系统会自动使用正确的大小。
“IntPtr”这个名字令人困惑——像Handle 这样的名字可能更合适。我最初的猜测是“IntPtr”是一个指针到一个整数。 MSDN documentation of IntPtr 涉及到一些神秘的细节,却没有提供太多关于名称含义的见解。
IntPtr 是一个有两个限制的指针:
换句话说,IntPtr 就像 void* 一样——但具有可以(但不应该)用于基本指针运算的额外功能。
为了取消对IntPtr 的引用,您可以将其转换为真正的指针(只能在“不安全”上下文中执行的操作),也可以将其传递给辅助例程,例如由InteropServices.Marshal 班级。使用Marshal 类会产生安全的错觉,因为它不需要您处于明确的“不安全”上下文中。但是,它并没有消除使用指针固有的崩溃风险。
【讨论】:
什么是指针?
在所有语言中,指针都是一种存储内存地址的变量,您可以要求他们告诉您他们所指向的地址或所在位置的值地址他们指向。
指针可以被认为是一种书签。除了用于快速跳转到书中的一页之外,指针用于跟踪或映射内存块。
将您的程序的内存想象成一个 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;
一旦将地址分配给指针,以下内容适用:
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# 中不安全指针的关系。
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
【讨论】:
这是处理IntPtr 的MSDN page。
第一行写着:
一种特定于平台的类型,用于表示指针或句柄。
至于页面继续状态的指针或句柄是什么:
IntPtr 类型可以被 支持指针的语言,以及 作为引用数据的常用手段 在做和不做的语言之间 支持指针。
IntPtr 对象也可用于 握住把手。例如,实例 IntPtr 被广泛用于 System.IO.FileStream 类持有 文件句柄。
指针是对存储您感兴趣的一些数据的内存区域的引用。
句柄可以是对象的标识符,并在双方都需要访问该对象时在方法/类之间传递。
【讨论】:
IntPtr 是 value type,主要用于保存内存地址或句柄。 pointer 是一个内存地址。指针可以有类型(例如int*)或无类型(例如void*)。 Windows handle 是一个通常与内存地址大小相同(或更小)的值,表示系统资源(如文件或窗口)。
【讨论】: