晚上有个同学给小C提了个问题:小C觉得还蛮典型的,发篇日志交流一下吧~
问题如下:
Device Development Kit里的一个宏
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
里面的(&((type *)0)->field)中的0怎么解释。
Device Development Kit,设备开发包。一般指Windows设备驱动程序开发包。那么MSDN里面应该有解释该宏的内容~小C找的是VS2008的帮助,顺便翻译下。
CONTAINING_RECORD
The CONTAINING_RECORD macro returns the base address of an instance of a structure given the type of the structure and the address of a field within the containing structure.
CONTAINING_RECORD 宏返回一个结构实例的基地址,该结构的类型和结构所包含的一个域(成员)地址已知。
PCHAR
-
Parameters
参数
Address
- Pointer to a field in an instance of a structure of type Type.
- 指向Type类型结构实例中某域(成员)的指针。 Type
- The name of the type of the structure whose base address is to be returned. For example, type IRP.
- 需要得到基地址的结构实例的结构类型名。 Field
- The name of the field pointed to by Address and which is contained in a structure of type Type.
- Type类型结构包含的域(成员)的名称。
-
Return Value
返回值
Returns the address of the base of the structure containing Field.
返回包含Field域(成员)的结构体的基地址。
Comments
注释
Called to determine the base address of a structure whose type is known when the caller has a pointer to a field inside such a structure. This macro is useful for symbolically accessing other fields in a structure of known type.
调用该宏计算出已知类型、已有一个域(成员)的指针的结构体的基地址。该宏有助于取得已知类型结构体的其他域(成员)的地址。
Callers of CONTAINING_RECORD can be running at any IRQL as long as the structure is resident. If a page fault might occur, callers must be at or below IRQL
只要结构体驻留在内存,CONTAINING_RECORD的调用程序(驱动)可以以任何中断优先级(IRQL)运行。如果可能发生页面故障,必须使得调用程序的中断优先级不高于APC_LEVEL.
Requirements
需求
Headers: Declared in ntdef.h. Include wdm.h or ntddk.h.
头文件:声明在ntdef.h中,需要包含wdm.h或ntddk.h.
(翻译得比较粗糙,可能有错误,希望大家纠正)
上面只是把MSDN里面的解释给大家贴了一下~大家基本应该明白这个宏是做什么的了~
也就是说这个宏根据给定的结构类型和一个结构体成员变量的地址来求结构体的基地址,进一步可以用来推出其他结构体成员变量的地址。
#define
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
那么我们拆开来看,前半部分——(PCHAR)(address)不很难理解吧,获取了成员变量的地址,关键点在后半部分那长长的一条——(ULONG_PTR)(&((type *)0)->field),一点点看,先看最里面的那三对括号——(&((type *)0)->field),首先看((type *)0),这句话,其实是得到了指向当0为type类型结构体的首地址时的field成员变量指针。那么再加上&这个取地址符,就是field成员变量到结构体首地址的偏移量。
这样的话:成员变量的地址-成员变量和结构体首地址间的偏移量,就是结构体的首地址了,蛮巧妙地应用。小C只是就语法上解释了这个宏,并没有实际应用的扩展,希望相关专业的同学能进行补充。