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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值