参考:
https://www.cnblogs.com/cdaniu/p/15789803.html
.NET提供了一个结构体System.IntPtr专门用来代表
句柄或指针
。
句柄是对象的标识符,当调用这些API创建对象时,它们并不直接返回指向对象的指针,而是会
返回一个32位或64位的整数值
,这个
在进程或系统范围内唯一的整数值就是句柄(Handle)
,随后程序再次访问对象,或者删除对象,都将句柄作为Windows API的参数来间接对这些对象进行操作。
-
句柄
指向就是指向文件开头,在windows系统所有的东西都是文件,对象也是文件。所以句柄和指针是一样的意思。句柄是面向对象的指针的称呼。
-
指针
是对存储区域的引用,该区域包含您感兴趣的一些数据。指针是面向过程编程的称呼。
intPtr类是
intPointer的缩写
。C#中用来取代指针,也可以说
对指针进行封装
。指向非托管内存。它也不常用,因为C#项目中指针都被弃用了,那指针的封装——句柄,自然也被弃用了。
但总有特殊的地方会用到指针,比如调用C++动态库之类的;所以微软贴心的为我们做了个句柄,毕竟指针用起来太难受了。
句柄是一个结构体
,简单的来说,它是指针的一个封装,是C#中指针的替代者,下面我们看下句柄的定义。
从图中我们可以看到,句柄IntPtrt里包含创建指针,获取指针长度,设置偏移量等等方法,并且为了编码方便还声明了些强制转换的方法。
看了句柄的结构体定义,相信稍微有点基础的人已经明白了,
在C#中,微软是希望抛弃指针而改用更优秀的intPtr代替它的。
但我们还会发现,句柄里还提供一个方法是ToPointer(),它的返回类型是Void*,也就是说,我们还是可以从句柄里拿到C++中的指针,既然,
微软期望在C#中不要使用指针
,那为什么还要提供这样的方法呢?
这是因为,
在项目开发中总是会有极特殊的情况
,比如,你有一段C++写的非常复杂、完美的函数,而将这个函数转换成C#又及其耗时,那么
最简单省力的方法就是直接在C#里启用指针进行移植
。
也就是说,
C#支持指针,其实是为了体现它的兼容性,并不是提倡大家去使用指针
。
参考:
https://zhidao.baidu.com/question/559571801.html
https://blog.csdn.net/lvjiyang/article/details/107040215
-
C#中的IntPtr类型被称之为“平台特定的整数类型”,用于
本机资源
,例如
窗口句柄
。
-
资源的大小取决于使用的硬件和操作系统
,即此类型的实例在32位硬件和操作系统中将是32位,在64位硬件和操作系统中将是64位;但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。
IntPtr 类型被设计成整数,其大小适用于特定平台。
-
在调用API函数时,类似含有窗口句柄参数(HANDLE)的原型函数,应显式地声明为IntPtr类型。
-
IntPtr类型对
多线程操作是安全的
。
-
IntPtr 类型可以由支持指针的语言使用,并可作为在支持与不支持指针的语言间引用数据的一种通用方式。
-
IntPtr 对象也可用于保持句柄。例如,IntPtr 的实例广泛地用System.IO.FileStream 类中来保持文件句柄。
、、、、、、、以下为补充、、、、、、、、、、、
-
IntPtr其实就是 HANDLE,无类型的指针。无类型的指针不能直接使用,需要传给接受它的函数。
-
托管window中的句柄,一般在window api 中使用, IntPtr a=(IntPtr)1;
例如:
一个C#程序调用Win32API mciSendString函数控制光盘驱动器,这个函数的
函数原型
是:
MCIERROR mciSendString(
LPCTSTR lpszCommand,
LPTSTR lpszReturnString,
UINT cchReturn,
HANDLE hwndCallback
首先在C#中声明这个函数:
[DllImport("winmm.dll")]
private static extern long mciSendString(string a,string b,uint c,IntPtr d);
然后用这样的方法调用:
mciSendString("set cdaudio door open", null, 0, this.Handle);
也可以使用IntPtr.Zero将句柄设置为0;
或者使用类型强制转换:
mciSendString("set cdaudio door open", null, 0, (IntPtr)0 );
或者,使用IntPtr构造函数:
IntPtr a = new IntPtr(2121);
完整代码:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApp5
class Program
[DllImport("winmm.dll")]
private static extern long mciSendString(string a, string b, uint c, IntPtr d);
static void Main(string[] args)
int Handle = 1;
mciSendString("set cdaudio door open", null, 0, (IntPtr)Handle);
mciSendString("set cdaudio door open", null, 0, IntPtr.Zero);
mciSendString("set cdaudio door open", null, 0, (IntPtr)0);
IntPtr a = new IntPtr(2121);
mciSendString("set cdaudio door open", null, 0, a);
Console.WriteLine("可以正确使用");
Console.ReadLine();
注意:
1、在C#中声明Win32API时,一定要按照WinAPI的原型来声明,不要改变它的数据类型;
2、尽量不要过多使用类型强制转换或构造函数的方式初始化一个IntPtr类型的变量,这样会使程序变得难于理解并容易出错。
参考:https://blog.csdn.net/lvjiyang/article/details/107040215
特别说明:下边示例均需启动“允许不安全代码”。
项目属性——>生成——>勾选“允许不安全代码”。
using System;
using System.Runtime.InteropServices;
namespace MyIntPtr
class Program
static void Main(string[] args)
int nValue1 = 10;
int nValue2 = 20;
IntPtr ptr1 = Marshal.AllocHGlobal(sizeof(int));
IntPtr ptr2 = Marshal.AllocHGlobal(sizeof(int));
Marshal.WriteInt32(ptr1, nValue1);
Marshal.WriteInt32(ptr2, nValue2);
int nVal1 = Marshal.ReadInt32(ptr1, 0);
int nVal2 = Marshal.ReadInt32(ptr2, 0);
Marshal.FreeHGlobal(ptr1);
Marshal.FreeHGlobal(ptr2);
Console.WriteLine("Test Success");
Console.ReadLine();
using System;
using System.Runtime.InteropServices;
namespace MyIntPtr
class Program
static void Main(string[] args)
string str = "aa";
IntPtr strPtr = Marshal.StringToHGlobalAnsi(str);
string ss = Marshal.PtrToStringAnsi(strPtr);
Marshal.FreeHGlobal(strPtr);
Console.WriteLine("Test Success");
Console.ReadLine();
using System;
using System.Runtime.InteropServices;
namespace MyIntPtr
class Program
public struct stuInfo
public string Name;
public string Gender;
public int Age;
public int Height;
static void Main(string[] args)
stuInfo stu = new stuInfo()
Name = "张三",
Gender = "男",
Age = 23,
Height = 172,
int nSize = Marshal.SizeOf(stu);
IntPtr intPtr = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(stu, intPtr, true);
stuInfo Info = (stuInfo)Marshal.PtrToStructure(intPtr, typeof(stuInfo));
Console.WriteLine(Info.Name);
Console.WriteLine(Info.Gender);
Console.WriteLine(Info.Age);
Console.WriteLine(Info.Height);
Console.WriteLine("Test Success");
Console.ReadLine();
运行结果:
https://learn.microsoft.com/zh-cn/dotnet/api/system.intptr?view=net-6.0
以下示例使用托管指针来反转数组中的字符。 初始化 String 对象并获取其长度后,它将执行以下操作:
-
Marshal.StringToHGlobalAnsi
调用该方法以 ANSI (单字节) 字符的形式将 Unicode 字符串复制到非托管内存。 该方法返回一个 IntPtr 对象,该对象指向非托管字符串的开头。 转换为指向字节的指针。
-
调用该方法 Marshal.AllocHGlobal
以分配与非托管字符串占用的字节数相同的字节数。 该方法返回一个 IntPtr 对象,该对象指向非托管内存块的开头。
-
Visual Basic 示例定义一个名为offset
等于 ANSI 字符串长度的变量。 它用于确定将 ANSI 字符串中下一个字符复制到的非托管内存中的偏移量。 由于其起始值为字符串的长度,因此复制操作会将字符串开头的字符复制到内存块的末尾。
C#、F# 和 C++ 示例调用 ToPointer
该方法以获取指向字符串起始地址和非托管内存块的非托管指针,并将一个小于字符串长度的字符串添加到 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;
IntPtr sptr = Marshal.StringToHGlobalAnsi(stringA);
IntPtr dptr = Marshal.AllocHGlobal(copylen + 1);
unsafe
byte *src = (byte *)sptr.ToPointer();
byte *dst = (byte *)dptr.ToPointer();
if (copylen > 0)
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);
Marshal.FreeHGlobal(dptr);
Marshal.FreeHGlobal(sptr);
运行结果:
通过Marshal.UnsafeAddrOfPinnedArrayElement(Array,Int32)
方法获得一个数组的第某个元素的内存地址。
- Array是数组
- Int32是元素的索引,第一个元素是0。
注:内存地址以字节为单位,第一个元素地址为n
,第二个为n+数据类型的字节数
。int32是4个字节,那么元素地相邻址之间差4。
using System;
using System.Runtime.InteropServices;
class ConsoleApp1
static public void Main()
int[] ary = new int[] { 1, 2, 3 };
IntPtr inp = Marshal.UnsafeAddrOfPinnedArrayElement(ary, 0);
IntPtr inp1 = Marshal.UnsafeAddrOfPinnedArrayElement(ary, 1);
IntPtr inp2 = Marshal.UnsafeAddrOfPinnedArrayElement(ary, 2);
Console.WriteLine(inp.ToString());
Console.WriteLine(inp1.ToString());
Console.WriteLine(inp2.ToString());
Console.ReadLine();
第1次运行结果:
第2次运行结果:
这里就要用到C#中的指针,用unsafe {}关键字,并设置:项目属性——>生成——>勾选“允许不安全代码”。
例如:【注:和指针p相关的变量只能出现在unsafe{}内部,外部无法使用】
using System;
using System.Runtime.InteropServices;
class ConsoleApp2
static public void Main()
int num = 999;
unsafe
int* p = #
Console.WriteLine((int)p);
Console.WriteLine(*p);
IntPtr op = new IntPtr((int)p);
Console.WriteLine(Marshal.ReadInt32(op));
Console.ReadLine();
运行结果:
C#学习汇总 - 总目录
C#中的IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。
资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。
例如,我们可以在vs2008中用C#做基于OpenCV的图像处理开发,下面两行代码就可以完成打开一幅图像的操作。
IntPtr img = CvInvoke.cvLoadImage(openFileDialog.FileName,
Emgu.CV.CvEnum.LOAD_IMAGE_TYPE.CV_LOAD_IMAGE_UNCHANGED);
CvInvoke.cvShowImage("打开图片", img);
一:什么是IntPtr
先来看看MSDN上说的:用于表示指针或句柄的平台特定类型。这个其实说出了这样两个事实,IntPtr 可以用来表示指针或句柄、它是一个平台特定类型。对于它的解释,这个哥们写的比较好:It's a class that
wraps a pointer that i
1.C#中的IntPtr类型被称之为“平台特定的整数类型”,用于本机资源,例如窗口句柄。
2.资源的大小取决于使用的硬件和操作系统,即此类型的实例在32位硬件和操作系统中将是32位,在64位硬件和操作系统中将是64位;但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。
3.在调用API函数时,类似含有窗口句柄参数(HANDLE)的原型函数,应显示地声明为IntPtr类型。
4.IntPtr类型对多线程操作是安全的。
5. int 和IntPtr互转
int i=1;
IntPtr p=new I
C# IntPtr数据类型相关操作byte[]转
IntPtr优点缺点
IntPtr转Stream参考链接
byte[]转
IntPtr
//输入buye[],返回
IntPtr
IntPtr ArrTo
Ptr(byte[] array)
return System.Runtime.
InteropServices.Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
不使用Marshal创建新的堆,节省内存开销,也避免忘记释放导致的问题
简单来说,这个东西是你创建出来的你就得负责回收,如果是你从别处那里借来用的,一般情况下你不需要负责回收。
https://social.msdn.microsoft.com/Forums/vstudio/zh-CN/da280694-f92c-42e6-afe2-6e126ef35955/-
intptr-?forum=2212
一、intptr_t类型
intptr_t 和uintptr_t 类型用来存放指针地址。它们提供了一种可移植且安全的方法声明指针,而且和系统中使用的指针长度相同,对于把指针转化成整数形式来说很有用,下面是这个类型的声明
#if __WORDSIZE == 64
# ifndef __intptr_t_defined
typedef long int intptr_t;
# define __intptr_t_defined
# endif
typedef unsigned l
C#中的IntPtr是一个结构体,表示一个指针或句柄的整数表示形式。它的大小与当前平台的指针大小相同,通常是32位或64位。在C#中使用IntPtr可以帮助我们在不同平台上编写可移植的代码,因为它可以自动调整指针的大小。
IntPtr通常用于与非托管代码进行交互,例如在C#中调用Win32 API函数时,我们需要将指针转换为IntPtr,以便在托管代码中使用。可以使用IntPtr的方法来执行指针操作,例如指针加法、比较和转换等。它还可以用于在C#中实现内存映射文件和其他高级IO操作。