Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15498102
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2007-10-18 10:46:59

浅析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;
}

阅读(7540) | 评论(2) | 转发(2) |
给主人留下些什么吧!~~

chinaunix网友2008-08-29 10:32:18

正心、修身、齐家、治国、平天下. 节选自:《礼记·大学》. 古之欲明明德于天下者,先治其国,欲治其国者,先齐其家;欲齐其家者,先修其身;欲修其身者,先正其心;