C-句柄其实就是一个Void*的指针,为什么要声明为Void*?
为什么句柄要声明为Void*?为什么不是窗口句柄就有一个窗口句柄类型,文件句柄就有文件句柄类型?这样不是更易读也更好用?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
为什么句柄要声明为Void*?为什么不是窗口句柄就有一个窗口句柄类型,文件句柄就有文件句柄类型?这样不是更易读也更好用?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(4)
在Visual C++头文件中有关句柄的定义如下:
#ifdef STRICT
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; };
typedef struct name##__ *name
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
在afxv_w32.h中有如下语句:
#ifndef STRICT
#define STRICT 1
#endif
因此,通常情况下,句柄的定义应该是:
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; };
typedef struct name##__ *name
定义中包含了两种句柄的定义:
一种是定义为void *的句柄HANDLE,
另一种是定义为name##__ *的句柄name。
可以发现返回HANDLE句柄的多是创建内核对象的函数,例如,CreateThread,CreateFile,CreateFileMapping,CreateSemaphore,因此依个人理解,HANDLE句柄是用来指向内核对象的指针。之所以定义成void型,估计是微软不想让人知道内核对象的真实内容。句柄指向内存中的内核对象,这个内核对象包含很多字段,其中有一个字段保存了真正要使用的对象的地址,其他字段还保存了对象的统计信息。
举例来说,当我们调用CreateThread时,创建了一个线程内核对象,并返回了一个线程句柄,这个句柄实际上指向了这个线程内核对象,而这个线程内核对象中包含了实际线程的许多信息,是用来管理线程的数据结构而已。当我们想访问这个线程时,只需要传递线程的句柄就可以,Windows知道该如何去解析。
另一种定义应该是用户对象句柄的定义,查看Visual C++源代码可以看到:
DECLARE_HANDLE(HDC);
DECLARE_HANDLE(HICON);
DECLARE_HANDLE(HMENU);
DECLARE_HANDLE(HMETAFILE);
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HPALETTE);
DECLARE_HANDLE(HPEN);
DECLARE_HANDLE(HRGN);
以DECLARE_HANDLE(HDC)为例来说,将宏展开可以得到如下的定义:
struct HDC__ { int unused; };
typedef struct HDC_ *HDC;
可以知道,HDC实际上是一个指向HDC_结构的指针,HDC_结构包含了一个整型变量,这个整型变量的值标识了一个要使用的对象。
主要有3方面原因
1、void 类型的指针不能执行++或者+n的操作
2、不能直接取空指针指向的内容
3、转换为其他类型指针时无需类型转换,例如 void * pVoid; int * pInt = pVoid;这样保证了即使为void类型后面使用也很方面
综上几点原因,可以使系统很好的保护句柄不被改变和破坏,又可以保证句柄作为指针时使用方便
个人觉得没有特别的原因,因为并不是所有的句柄都是 void * 啊,其实用int型或者int *做句柄的设计案例也有很多的。
windows SDK已经定义了各种类型的句柄,HANDLE, HWND 等, 有的是用void* 定义,有的是用int定义的