对CONTAINING_RECORD的理解

晚上有个同学给小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  CONTAINING_RECORD(
    IN PCHAR  
Address,
    IN TYPE  
Type,
    IN PCHAR  
Field
    );

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 = APC_LEVEL.

只要结构体驻留在内存,CONTAINING_RECORD的调用程序(驱动)可以以任何中断优先级(IRQL)运行。如果可能发生页面故障,必须使得调用程序的中断优先级不高于APC_LEVEL.

Requirements

需求

Headers: Declared in ntdef.h. Include wdm.h or ntddk.h.

头文件:声明在ntdef.h中,需要包含wdm.hntddk.h.

(翻译得比较粗糙,可能有错误,希望大家纠正)

上面只是把MSDN里面的解释给大家贴了一下~大家基本应该明白这个宏是做什么的了~

也就是说这个宏根据给定的结构类型和一个结构体成员变量的地址来求结构体的基地址,进一步可以用来推出其他结构体成员变量的地址。

#define CONTAINING_RECORD(address, type, field) ((type *)( \

(PCHAR)(address) - \

(ULONG_PTR)(&((type *)0)->field)))

那么我们拆开来看,前半部分——(PCHAR)(address)不很难理解吧,获取了成员变量的地址,关键点在后半部分那长长的一条——(ULONG_PTR)(&((type *)0)->field),一点点看,先看最里面的那三对括号——(&((type *)0)->field),首先看((type *)0),这句话,其实是得到了指向当0为type类型结构体的首地址时的field成员变量指针。那么再加上&这个取地址符,就是field成员变量到结构体首地址的偏移量。

这样的话:成员变量的地址-成员变量和结构体首地址间的偏移量,就是结构体的首地址了,蛮巧妙地应用。小C只是就语法上解释了这个宏,并没有实际应用的扩展,希望相关专业的同学能进行补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值