发布网友 发布时间:2024-10-23 17:20
共1个回答
热心网友 时间:2024-11-04 10:05
编程领域中,句柄是一个常见术语。根据百度百科的说明,句柄是用来标识对象或项目的标识符,可用于描述窗体、文件等。为了深入理解句柄,以下通过MATLAB中的function handle为例进行阐述。MATLAB官方文档对function handle的定义和描述如下:
function handle是MATLAB®的一种数据类型,用于存储函数的关联。间接调用函数允许你从任意位置调用函数。function handle的典型用途包括:1. 将函数传递给另一个函数(通常称为函数函数)。例如,将函数传递给积分和优化函数,如integral和fzero。2. 指定回调函数。例如,响应UI事件或与数据采集硬件交互的回调。3. 构造指向在程序文件中定义而不是存储的函数的句柄(匿名函数)。4. 从主函数外部调用局部函数。要创建一个函数句柄,请在函数名称前加上@符号。例如,如果你有一个名为myfunction的函数,创建一个名为f的句柄如下:f = @myfunction;
简而言之,函数句柄是一种数据类型,它提供了一种接口,让你可以在任意位置间接调用与之关联的函数。然而,为何要使用句柄呢?函数指针难道不行吗?
为什么不使用函数指针或首地址?
在Windows系统中,有许多内核对象,如打开的文件、创建的线程、程序的窗口等。这些重要对象的状态通常需要上百甚至上千字节的内存空间来保存。为了在程序间或程序内部的子过程(函数)之间传递这些数据,如何处理这些数据呢?显然,拖动这些成百上千的字节进行复制会浪费效率。那么怎么办?当然,传递这些对象的首地址是一种方法,但这至少有两个缺点:1. 暴露了内核对象本身,使得程序(而不是操作系统内核)可以任意修改对象的内部状态;2. 操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被移动了怎么办?因此,Windows操作系统采用进一步的间接方法:在进程的地址空间中设一张表,专门保存一些编号和与这些编号对应的地址,而由这些地址去引用实际的对象。在Windows系统中,这个编号就叫做"句柄"。也就是说,如果不在乎浪费空间的话,在某些情况下可以不使用句柄,直接对文件进行操作。从广义上讲,能够从一个数值提取一大堆数据的东西都可以称为句柄。句柄的英文是"Handle",本义是"柄",在计算机科学中,被特别地翻译成"句柄",其实还是个"柄"。从一个小东西提取一大堆东西,这不就像是个"柄"吗?然后,指针其实也是一种"句柄",只是由于指针同时拥有更特殊的含义——实实在在地对应内存中的一个地址——所以,通常不把指针说成是"句柄"。但指针也有着能从一个32位的值提取到一大堆数据的作用,这难道不是句柄吗?
handle与进程ID、HINSTANCE的区别
1. Handle:Handle本身是一个32位的无符号整数,用于代表一个内核对象。它并不指向实际的内核对象,用户模式下的程序永远不可能获得一个内核对象的实际地址。Handle的意义在于,它实际上作为一个索引在表中查找对应的内核对象的实际地址。这个表在哪里?每个进程都有一个这样的表,称为句柄表。该表的第一项是进程自己的句柄,这也是为什么你调用GetCurrentProcess()总是返回0x7FFFFFFF的原因。简而言之,Handle是一种用来"间接"代表一个内核对象的整数值。你可以在程序中使用handle来代表你想要操作的内核对象。这里的内核对象包括:事件(Event)、线程、进程、Mutex等。要注意的是,Handle仅在其所属的进程中才有意义。将一个进程拥有的handle传递给另一个进程没有任何意义,如果非要这么做,则需要使用DuplicateHandle(),在多个进程间传递Handle是另一个话题,与这里要讨论的无关。
2. 进程ID:进程ID是一个32位无符号整数,每个进程都有一个这样的ID,并且该ID在系统范围内是唯一的。系统使用该ID来唯一确定一个进程。深入地说,系统可能使用进程ID来计算代表该进程的内核对象的基地址(及EPROCESS结构的基地址),具体的计算公式你可以去问微软的OS开发人员。
3. HINSTANCE:HINSTANCE也是一个32位无符号整数,表示程序加载到内存中的基地址。