找回密码
 加入计匠网
搜索
热搜: BIOS ACPI CPU Windows
查看: 10502|回复: 3

[原创]CONTAINING_RECORD IN EFI

[复制链接]
发表于 2009-10-15 18:06:17 | 显示全部楼层 |阅读模式
CONTAINING_RECORD IN EFI
! ]/ a$ V: S5 Z3 W: D* M1 F8 y
: A. @1 i9 x6 E! [2 G5 q0 }
EFI BIOS几乎全部用C完成,它几乎将C语言的各种技巧发挥到了极致。C的精髓泰半是指针,另外宏也是非常值得称道的。程序员对于宏的评价可谓褒贬不一,有人说它是万恶之源,有人则赞其为一把利刃。我个人觉得运用之妙,存乎一心,宏不是万能的,但是有一些场合使用宏确实可以大大的提高程序的可读性,有些跨平台的特性离开了宏还真是不行。_CREFI之中经常会被用的宏,我们来看看它的庐山真面目吧:
2 C* ^/ Q1 X8 H3 V4 c# [( d

2 A/ V' J+ H8 c' ^4 D$ H) _, Q, ~
//

7 O+ _+ D! O: q5 j
//8 c1 A3 {& M9 y$ G
CONTAINING_RECORD - returns a pointer to the structure

# n/ K- ?1 |/ b% E- w
//) D' w6 g6 X# {. J
from one of it's elements.
6 V+ K# o6 x5 ~8 l
//
: E8 c, s% j6 _# c  o& G) ~2 E
#define _CR(Record, TYPE, Field)* n$ l) ?* z# T6 m2 C3 w# {
((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))

8 U2 P! y; M' M这个宏的作用是根据一个结构体成员变量的的地址获得该结构体基地址。举例如下:! e" }( t# B  U. Q0 X! Y  f
struct _Test; |, T: P4 Q5 }2 j4 E
{6 X( w& }: s1 P3 a/ S4 P6 U& c
CHAR8 t0;

8 J% ?6 R6 J& M- n/ S8 {; [: Y& K: E+ C
UINT16 t1;

4 w0 \! a( n! T( y6 o0 [' H5 U0 I" S# _4 f  `: ~) P) Q5 p
UINT8   t2;

. l2 N* @! z3 D- o- r- {3 F5 q: ^$ U% @, R7 K
UINT32  t3;
6 x+ }5 Q( j9 d! Q: l9 O' ~6 L
};
1 h, U" g3 n* ]4 N3 R# |1 x9 l# I& T3 f' z5 k, l
我们在某一个地方获得了t2的地址t2Ptr,这时如果要得到t2所在结构体的基地址就可以这样做:struct _Test* bPtr = _CR(t2Ptr,struct _Test,t2);预处理展开之后就是这副样子 struct _Test* bPtr = ((struct _Test*)((CHAR8*)(t2Ptr)-(CHAR8*)&((struct _Test *)0)->t2),其实我觉得关键的部分在这句“(TYPE *) 0)->Field”,它其实就是获得该成员在结构体中的偏移位置(offset),该成员变量的地址减去它在结构体中的偏移也就获得了基地址了。
7 f1 }# Z4 X& @( V% D8 \* |' \. i: u3 H% A7 b. n: e: N9 K

7 F0 K* J+ |% O* Y3 K一图胜千言,如上图所示,假设t2的地址是0x1005,那么bPtr应该是多少呢?我们只要用t2-t2offset0x03)即可,也就是0x1002。是不是很简单?
& q0 e0 s  N3 E
& j- ~9 m- ~/ h3 N大概是英雄所见略同吧,这种形式的宏在Linux kernel Windows Kernel中也都有存在,只不过名字叫的不一样罢了。先看看Linux下长的什么样子吧:0 T% q! L0 }/ Z
/**

4 d1 j3 J( ?4 ?; {: m( q

3 `9 t. E* g' `/ {# K0 U' J6 y* container_of - cast a member of a structure out to the containing structure

* [/ K2 L  r" Z/ h7 R; a

9 u% a( a) {( V" T: U/ X! M0 [/ W5 ^*

/ }" g% H6 V6 J1 A! H6 b& I

6 i$ j  I! ^4 V% a! z, X* @ptr:2 C" A% J0 t$ R1 L8 _
the pointer to the member.

5 r8 z' [* l& o$ [- Y: B$ F1 w+ I, X3 A
& P+ N! [+ o: j* z7 x2 G
* @type:0 [1 ^( [4 M% R
the type of the container struct this is embedded in.
0 ]" |" R  W: d2 X6 V

9 [* O" \! c, `( A  ~* @member:7 C* A3 ~- c! j2 p7 z( O5 t9 I3 M
the name of the member within the struct.
3 u1 c. m5 p5 B5 [3 V% v; i

( Y. C6 H- O/ z& N# g*
* q6 l) `7 o* j5 V8 h

5 X9 p1 H  b& U5 I( A*/

& D5 L- ]$ }- o# K7 f#define
, K/ p& F2 m1 {5 F+ ]# @! Zcontainer_of(ptr, type, member) ({' S- q- t% G7 p$ |/ h6 K
\
" i. _. q; X6 V+ \( f+ o

+ d' K6 P, ^/ j! i4 B' Pconst typeof( ((type *)0)->member ) *__mptr = (ptr);
, c7 x+ {  c- H  |0 {9 ?+ D\

2 |4 O( c4 q, w$ e4 Y; e3 X# N
/ r% v/ z3 v8 g+ X- {) {1 p(type *)( (char *)__mptr - offsetof(type,member) );})

5 K7 v2 O" i8 i. H0 T' m+ K. K- p4 R
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)$ M( |) }0 E4 Y. y6 I

; ~* D* W. p& m再来看看它在Windows Kernel中的小模样J:- g% o6 u5 R$ x4 C% G* ^" a7 Y
#define* p' B8 m3 q; ^
CONTAININT_RECORD(address, type, field) \2 J! x7 D1 y4 R4 e
             ((type*)((PCHAR)(address) - (PCHAR)(&((type*)0)->field)))

+ ^; w7 V2 [- F4 G. T* ^2 c( Y1 M他们的作用都是一样的,是不是有点天下文章一大抄的感觉啊,呵呵
. T- q+ ?3 L  ]6 R
' A; D- O+ O+ s. s' A" M9 i1 B
2 t1 B" |+ R; h" a
% g) W7 y0 T+ f" I; gPeter3 n( J4 x2 c: k7 z% f

7 `5 V. K1 n, B. _; B2009-10-6

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入计匠网

×
发表于 2009-10-23 15:42:14 | 显示全部楼层
顺楼主者昌,逆楼主者亡.
回复

使用道具 举报

发表于 2009-10-26 09:49:54 | 显示全部楼层
象这样的宏挺绕人的,但又经常会碰到。
4 H1 g) `4 \1 i/ T  i+ Y6 c楼主将其重点突出,从而问题变得很直接很明了了。。顶一个哈
回复

使用道具 举报

发表于 2009-10-30 22:51:12 | 显示全部楼层
崇拜中。。。。。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入计匠网

本版积分规则

Archiver|手机版|小黑屋|计匠网

GMT+8, 2026-9-21 10:20 , Processed in 0.061923 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表