#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

該宏在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的入口地址)減去通用鏈表結構體成員變量在該數據結構體變量中的在偏移量,獲得的結果就是該數據結構體變量的入口地址。
 spa

 

通用鏈表的應用實例:指針

#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);
相關文章
相關標籤/搜索