#define list_entry(ptr, type, member) \   container_of(ptr, type, member)

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

该宏在Linux内核代码(版本2.6.22)中定义如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER);
分析:
(TYPE *)0,将 0 强制转换为 TYPE 型指针,记 p = (TYPE *)0,p是指向TYPE的指针,它的值是0。那么 p->MEMBER 就是 MEMBER 这个元素了,而&(p->MEMBER)就是MENBER的地址,而基地址为0,这样就巧妙的转化为了TYPE中的偏移量。再把结果强制转 换为size_t型的就OK了,size_t其实也就是int。
typedef __kernel_size_t  size_t;
typedef unsigned int __kernel_size_t;
可见,该宏的作用就是求出MEMBER在TYPE中的偏移量。
 

关于typeof,这是gcc的C语言扩展保留字,用于声明变量类型.
const typeof( ((type *)0->member ) *__mptr = (ptr);意思是声明一个与member同一个类型的指针常量 *__mptr,并初始化为ptr.也就是该数据结构体中通用链表成员变量的地址。即member的入口地址
(type *)( (char *)__mptr - offsetof(type,member) );意思是__mptr的地址减去member在该struct中的偏移量得到的地址, 再转换成type型指针. 该指针就是member的入口地址了.
在一个数据结构体变量通用链表结构体成员变量所在的地址(也就是member的入口地址)减去通用链表结构体成员变量在该数据结构体变量中的在偏移量,得到的结果就是该数据结构体变量的入口地址。
 

003549_NhJB_2515635.png

 

通用链表的应用实例:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");
MODULE_DESCRIPTION("List Module");
MODULE_ALIAS("List module");

struct student
{
    char name[100];
    int num;
    struct list_head list;
};

struct student *pstudent;
struct student *tmp_student;
struct list_head student_list;
struct list_head *pos;

int mylist_init(void)
{
	int i = 0;
	
	INIT_LIST_HEAD(&student_list);
	
	pstudent = kmalloc(sizeof(struct student)*5,GFP_KERNEL);
	memset(pstudent,0,sizeof(struct student)*5);
	
	for(i=0;i<5;i++)
	{
	    sprintf(pstudent[i].name,"Student%d",i+1);
		pstudent[i].num = i+1; 
		list_add( &(pstudent[i].list), &student_list);
	} 
	
	
	list_for_each(pos,&student_list)
	{
		tmp_student = list_entry(pos,struct student,list);
		printk("<0>student %d name: %s\n",tmp_student->num,tmp_student->name);
	}
	
	return 0;
}


void mylist_exit(void)
{	
	int i ;
	/* 实验:将for换成list_for_each来遍历删除结点,观察要发生的现象,并考虑解决办法 */
	for(i=0;i<5;i++)
	{
		list_del(&(pstudent[i].list));     
	}
	
	kfree(pstudent);
}

module_init(mylist_init);
module_exit(mylist_exit);

 

转载于:https://my.oschina.net/u/2515635/blog/781149

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值