您的位置:首页 > 大数据 > 人工智能

浅析container_of(ptr, type, member)

2012-01-06 14:32 531 查看
#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 conststruct 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息