百度收录左侧带图片的网站品牌营销策略四种类型
内核双向链表的数据结构
他只有两个指针域,没有数据域,但是这样他的通用性得到了优化,但是这样没有数据,有什么意义呢,我们先来看看内核提供的接口函数
struct list_head
{struct list_head *next,*head;
};
链表的创建函数,创建一个结点,并初始化
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
链表的插入的头插法
static inline void list_add(struct list_head *new, struct list_head *head) {__list_add(new, head, head->next);}static inline void __list_add(struct list_head *new, struct list_head *prev,struct list_head *next){next->prev = new;new->next = next;new->prev = prev;prev->next = new;}
链表的尾插法
74 static inline void list_add_tail(struct list_head *new, struct list_head *head) 75 {76 __list_add(new, head->prev, head);77 }static inline void __list_add(struct list_head *new, struct list_head *prev,struct list_head *next){next->prev = new;new->next = next;new->prev = prev;prev->next = new;}
链表的删除
static inline void __list_del(struct list_head * prev, struct list_head * next) {next->prev = prev;prev->next = next;}static inline void list_del(struct list_head *entry) {__list_del(entry->prev, entry->next);entry->next = LIST_POISON1; //指向两个无效的地址entry->prev = LIST_POISON2;}
链表的遍历
#define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)
写一个测试程序测试一下
#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>
#define N 128struct stu{char name[100];int id;int math;struct list_head list;
};LIST_HEAD (head);
static int demo_init (void)
{int i,ret;struct stu *stu;struct list_head *pos;for (i=0;i<N;i++){stu =kmalloc(sizeof(*stu),GFP_KERNEL);if (NULL==stu) {ret=-ENOMEM;goto error0;}stu->id =9527+i;sprintf (stu->name,"chouchou%d",i);stu ->math = (60+i)%101;list_add_tail(&stu->list,&head);}list_for_each(pos,&head) {stu=container_of(pos,struct stu,list);printk ("-------id %d -------\n",stu->id);printk ("name %s , math: %d\n",stu->name,stu->math);}return ret;
error0:return ret;}
module_init (demo_init);static void demo_exit (void)
{struct list_head *pos,*n;struct stu*stu;list_for_each_safe(pos,n,&head){stu =container_of(pos,struct stu,list);kfree (stu);}
}module_exit (demo_exit);
container_of宏的理解
我们刚才在上面看双向循环链表结构的时候发现,他没有数据域,所以我们怎么知道他的数据,在上面的测试程序中我们使用了container_of这个宏来返回一个指针,其中就包含数据,所以我们来看一下container_of这个宏怎么得到数据
/**
677 * container_of - cast a member of a structure out to the containing structure
678 * @ptr: the pointer to the member.
679 * @type: the type of the container struct this is embedded in.
680 * @member: the name of the member within the struct.
681 *
682 */#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
683 #define container_of(ptr, type, member) ({ \
684 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
685 (type *)( (char *)__mptr - offsetof(type,member) );})
来大概理解一下这个宏,他的核心思想就是通过知道你定义的类型指针,定义的类型,还有成员的名字来确定出包含这个链表的结构体的地址,从而获取数据域
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ //将ptr的类型指针赋值给通过tyoeof新类型的变量__mptr(type *)( (char *)__mptr - offsetof(type,member) );})#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)//将0地址转换为指针并指向成员再通过取地址操作得到偏移量//再用成员的地址减去偏移地址就得到结构体的首地址,再将他强转为目标结构体类型