container_of()和内核链表中的list_entry()

(1) container_of宏的原始定义是:  

/**
* container_of - cast a member of a structure out to the containing structure
* @ptr:    the pointer to the member.
* @type:   the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
* */

#define container_of(ptr, type, member) ({                    /        
        const typeof( ((type *)0)->member ) *__mptr = (ptr); -/
        (type *)( (char *)__mptr - offsetof(type,member) );})

       该宏的作用是:指针ptr是指向结构体type中的成员member;通过指针ptr,该宏返回结构体type的起始地址。模型如下:

          type
      |----------|
      |          |
      |          |
      |----------|
ptr-->| member --|
      |----------|
      |          |
      |          |
      |----------|

        分析可知__mptr指向的是一个type结构里typeof(((type *)0)->member)类型member成员的指针,offsetof(type,member)是这个成员member在结构type中的偏移,单位是字节,所以为了计算type结构的起始地址,__mptr减去它自己的偏移。

说明:TYPE是某struct的类型,0是一个假想TYPE类型struct地址,MEMBER是该struct中的一个成员;由于该struct的基地址为0, MEMBER的地址就是该成员相对与struct头地址的偏移量。const typeof( ((type *)0->member ) *__mptr = (ptr);意思是声明一个与member同一个类型的指针常量 *__mptr,并初始化为ptr。(type *)( (char *)__mptr - offsetof(type,member) );意思是__mptr的地址减去member在该struct中的偏移量得到的地址, 再转换成type型指针,该指针就是member所在结构体的入口地址了。

例一,通过一个程序来验证

include<stdio.h>
struct student{
    char name[20];  
    char sex;
}stu={"zhangsan",'m'};
main()
{
      struct student *stu_ptr;    //存储container_of宏的返回值
      int offset;                          //存储offsetof宏的返回值
      const typeof(((struct student*)0)->sex) *_mptr = &stu.sex;
      offset = (int)(&((struct student *)0)->sex);
      stu_ptr = (struct student *)((char*)_mptr - offset);
      printf("offsetof stu.sex = %d/n",offset);  //输出偏移
      printf("stu_ptr->name:%s/tstu_ptr->sex:%c/n", stu_ptr->name, stu_ptr->sex);
      return 0;
}

        综上那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。至于offsetof的用法,我们同样可以采用一段程序来说明:

struct student 
{
     char name[20];
     char sex;
};
main()
{
      printf("value is %d /n",(unsigned int)&((struct student *)0)->sex);
}

        结果得20,恰为偏移值。

(2)list_entry宏的定义

/**
 * list_entry - get the struct for this entry
 * @ptr:	the &struct list_head pointer.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_struct within the struct.
 */
#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

       该宏的作用是根据链表的一个成员可以访问链表结构的其他成员。比如如下的一个结构体:

struct demo{

      long data;

      struct list_head list;

}

在知道成员变量list地址(假设Ptr)的情况下,通过list_entry(Ptr,struct demo,list)->data即可访问成员变量data。由此延伸出来的内核遍历函数list_for_each_entry就是基于这个宏实现的:

/**
 * list_for_each_entry	-	iterate over list of given type
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#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))

       其中,head是个链表头,它是pos结构体中的成员,member就是struct list_head的list。如:

struct i2c_devinfo {
       struct list_head list;
       int   busnum;
       struct i2c_board_info board_info;
};

struct list_head __i2c_board_list;

struct i2c_devinfo *devinfo;

list_for_each_entry(devinfo, &__i2c_board_list, list)
 


原文地址:http://blog.csdn.net/yinkaizhong/archive/2009/04/20/4093795.aspx

你可能感兴趣的:(c,list,struct,存储,each,structure)