8.2 KiB
#unity/日常积累
IntPtr 结构
- 参考
反馈
定义
命名空间:
程序集:
System.Runtime.dll
Source:
表示一个带符号整数,其中位宽度与指针相同。
示例
以下示例使用托管指针来反转数组中的字符。 初始化 对象 String 并获取其长度后,它会执行以下操作:
-
调用 方法, Marshal.StringToHGlobalAnsi 将 Unicode 字符串作为 ANSI (单字节) 字符复制到非托管内存。 方法返回一个 IntPtr 对象,该对象指向非托管字符串的开头。 Visual Basic 示例直接使用此指针;在 C++、F# 和 C# 示例中,它被强制转换为指向字节的指针。
-
Marshal.AllocHGlobal调用 方法以分配与非托管字符串占用的相同字节数。 方法返回一个 IntPtr 对象,该对象指向非托管内存块的开头。 Visual Basic 示例直接使用此指针;在 C++、F# 和 C# 示例中,它被强制转换为指向字节的指针。
-
Visual Basic 示例定义一个名为
offset
的变量,该变量等于 ANSI 字符串的长度。 它用于确定将 ANSI 字符串中的下一个字符复制到的非托管内存中的偏移量。 由于其起始值为字符串的长度,因此复制操作会将字符从字符串的开头复制到内存块的末尾。C#、F# 和 C++ 示例调用 ToPointer 方法以获取指向字符串的起始地址和非托管内存块的非托管指针,并将小于字符串长度的指针添加到 ANSI 字符串的起始地址。 由于非托管字符串指针现在指向字符串的末尾,因此复制操作会将字符串末尾的字符复制到内存块的开头。
-
使用循环将字符串中的每个字符复制到非托管内存块。
Visual Basic 示例调用 Marshal.ReadByte(IntPtr, Int32) 方法,以从指向 ANSI 字符串的托管指针的指定偏移量读取字节 (或单字节字符) 。 偏移量随循环的每次迭代而递增。 然后, Marshal.WriteByte(IntPtr, Int32, Byte) 它调用 方法,将字节写入由非托管内存块的起始地址和
offset
定义的内存地址。 然后,它会递offset
减 。C#、F# 和 C++ 示例执行复制操作,然后递减指向非托管 ANSI 字符串中下一个位置的地址的指针,并将指针递增到非托管块中的下一个地址。
-
所有示例都调用 Marshal.PtrToStringAnsi ,将包含复制的 ANSI 字符串的非托管内存块转换为托管的 Unicode String 对象。
-
在显示原始字符串和反向字符串后,所有示例都会调用 FreeHGlobal 方法来释放为非托管 ANSI 字符串和非托管内存块分配的内存。
using System;
using System.Runtime.InteropServices;
class NotTooSafeStringReverse
{
static public void Main()
{
string stringA = "I seem to be turned around!";
int copylen = stringA.Length;
// Allocate HGlobal memory for source and destination strings
IntPtr sptr = Marshal.StringToHGlobalAnsi(stringA);
IntPtr dptr = Marshal.AllocHGlobal(copylen + 1);
// The unsafe section where byte pointers are used.
unsafe
{
byte *src = (byte *)sptr.ToPointer();
byte *dst = (byte *)dptr.ToPointer();
if (copylen > 0)
{
// set the source pointer to the end of the string
// to do a reverse copy.
src += copylen - 1;
while (copylen-- > 0)
{
*dst++ = *src--;
}
*dst = 0;
}
}
string stringB = Marshal.PtrToStringAnsi(dptr);
Console.WriteLine("Original:\n{0}\n", stringA);
Console.WriteLine("Reversed:\n{0}", stringB);
// Free HGlobal memory
Marshal.FreeHGlobal(dptr);
Marshal.FreeHGlobal(sptr);
}
}
// The progam has the following output:
//
// Original:
// I seem to be turned around!
//
// Reversed:
// !dnuora denrut eb ot mees I
注解
类型 IntPtr 设计为一个整数,其大小与指针相同。 也就是说,此类型的实例应在 32 位进程中为 32 位,在 64 位进程中为 64 位。
支持 IntPtr 指针的语言可以使用 类型,并作为在支持和不支持指针的语言之间引用数据的常用方法。
IntPtr 对象还可用于保存句柄。 例如, 的 IntPtr 实例在 类中 System.IO.FileStream 广泛使用,用于保存文件句柄。
备注
使用 IntPtr 作为指针或句柄容易出错且不安全。 它只是一个整数类型,由于大小相同,可用作指针和句柄的交换格式。 在特定的交换要求(例如,将数据传递给不支持指针的语言)之外,应使用正确类型的指针来表示指针,并 SafeHandle 应用于表示句柄。
此类型实现 ISerializable。 在 .NET 5 及更高版本中,此类型还实现 IFormattable 接口。 在 .NET 7 及更高版本中,此类型还实现 IBinaryInteger、 IMinMaxValue和 ISignedNumber 接口。
在从版本 9.0 开始的 C# 中,可以使用内置 nint
类型定义本机大小的整数。 此类型在内部由 IntPtr 类型表示,并提供适用于整数类型的操作和转换。 有关详细信息,请参阅 nint 和 nuint 类型。
在 C# 中,从版本 11 开始,以 .NET 7 或更高版本运行时为目标时, nint
是 的 IntPtr 别名,其别名与 int
的别名 Int32相同。