您的位置:首页 > 运维架构 > Linux

(转载)浅析linux 内核代码中的container_of(ptr, type, member)宏

2010-05-30 22:06 846 查看
浅析container_of(ptr, type, member)

浅析container_of(
ptr,
type,
member)

文章来源:
http:
//gliethttp.cublog.cn

#
define
container_of(
ptr,
type,
member)
(
{
                  /

    const
typeof
(
(
(
type *
)
0)
-
>
member )
*
__mptr =
(
ptr)
;
    /

    (
type *
)
(
(
char
*
)
__mptr -
offsetof
(
type,
member)
)
;
}
)

#
define
offsetof
(
TYPE,
MEMBER)
(
(
size_t
)
&
(
(
TYPE *
)
0)
-
>
MEMBER)

1.
ptr为物理地址,
其类型和member类型一致,
最终使用typeof(
(
(
type *
)
0)
-
>
member )

  由编译器自动返回member的类型

2.
type为包含member成员的结构体

3.
offsetof
(
type,
member)
为member成员在type结构体中的偏移值,
大小范围0~
sizeof
(
type)
字节

 (
因为以0地址为type类型数据结构的起始地址)

4.
ptr-
offsetof
(
)
就等于包含该ptr的type结构体父变量的物理起始地址,
强制转换为(
type*
)
.

应用举例:

#
define
list_entry(
ptr,
type,
member)
                         /

    container_of(
ptr,
type,
member)

#
define
list_for_each_entry(
pos,
head,
member)
                /

    for
(
pos =
list_entry(
(
head)
-
>
next,
typeof
(
*
pos)
,
member)
;
/

     prefetch(
pos-
>
member.
next)
,
&
pos-
>
member !
=
(
head)
;
     /

     pos =
list_entry(
pos-
>
member.
next,
typeof
(
*
pos)
,
member)
)

//-------------------------------------------------------------

list_entry(
(
head)
-
>
next,
typeof
(
*
pos)
,
member)
返回(
head)
-
>
next物理指针所处位置向前减去offsetof(
)
个字节数据之后,
其父变量pos的物理地址,
父变量的类型在编译时由typeof(
*
pos)
自动返回(
gliethttp)
.

所以list_for_each_entry遍历head下面挂接的类型为typeof(
*
pos)
的childs结构体们,
当然每个child结构体包含struct list_head node之类相似的双向链表list_head类型项,
就这样通过循环pos将依次指向双向链表上的各个child.
(
member就是child类型中被定义的变量名)

//-------------------------------------------------------------

下面一段程序摘自:
drivers/
usb/
driver.
c
struct
usb_dynids {

    spinlock_t lock;

    struct
list_head list
;

}
;

struct
usb_dynid {

    struct
list_head node;

    struct
usb_device_id id;

}
;

static
const
struct
usb_device_id *
usb_match_dynamic_id(
struct
usb_interface *
intf,

                            struct
usb_driver *
drv)

{

    struct
usb_dynid *
dynid;

    spin_lock(
&
drv-
>
dynids.
lock)
;

//gliethttp_20071018

//1. drv->dynids.list为head,即:树根,父亲,正如上面的struct usb_dynids

//2. dynid为child,其中drv->dynids.list.next存放了第一个child结构体中的

//   struct list_head类型名字为node的物理地址值.

//3. 看着很复杂,其实翻译出来就简单多了(gliethttp)

//模型为for(child;child != head;child = child->next)

// for(dynid = container_of(drv->dynids.list.next, struct usb_dynid,nod);

//     dynid->node != &drv->dynids.list;

//     dynid = container_of(dynid->node.next, struct usb_dynid,nod)

//     )

    list_for_each_entry(
dynid,
&
drv-
>
dynids.
list
,
node)
{

        if
(
usb_match_one_id(
intf,
&
dynid-
>
id)
)
{

            spin_unlock(
&
drv-
>
dynids.
lock)
;

            return
&
dynid-
>
id;

        }

    }

    spin_unlock(
&
drv-
>
dynids.
lock)
;

    return
NULL
;

}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息