C-句柄其实就是一个Void*的指针,为什么要声明为Void*?

发布于 2017-01-27 01:48:46 字数 67 浏览 1656 评论 4

为什么句柄要声明为Void*?为什么不是窗口句柄就有一个窗口句柄类型,文件句柄就有文件句柄类型?这样不是更易读也更好用?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

灵芸 2017-08-31 11:38:39

在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_结构包含了一个整型变量,这个整型变量的值标识了一个要使用的对象。

归属感 2017-08-29 15:09:39

主要有3方面原因
1、void 类型的指针不能执行++或者+n的操作
2、不能直接取空指针指向的内容
3、转换为其他类型指针时无需类型转换,例如 void * pVoid; int * pInt = pVoid;这样保证了即使为void
类型后面使用也很方面
综上几点原因,可以使系统很好的保护句柄不被改变和破坏,又可以保证句柄作为指针时使用方便

归属感 2017-06-23 09:20:51

个人觉得没有特别的原因,因为并不是所有的句柄都是 void * 啊,其实用int型或者int *做句柄的设计案例也有很多的。

偏爱自由 2017-03-19 13:57:47

windows SDK已经定义了各种类型的句柄,HANDLE, HWND 等, 有的是用void* 定义,有的是用int定义的

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文