LinuxKernel 入侵式双向链表的设计,分析,使用

#PS:请尊重原创,不喜勿喷


#PS:要转载请注明出处,本人版权所有


#PS:这个只是  《  我自己    》理解,如果和你的原则相冲突,请


谅解,勿喷 


链表按照实现原理我分为两类,一是普通的链表,二是入侵式链表。(区别就是,链表结构体里面有没有数据)。


由于我重写了Linux 链表的实现,部分东西被我更改,所以文中代码以我的实际代码为例。

下面围绕几点来理解一下:

链表元素结构体声明:

typedef struct y_list_head {
struct y_list_head *next;
struct y_list_head *prev;
} Y_LISTHEAD;

 
节点元素结构体声明: 

typedef struct {
int a;
Y_LISTHEAD list;
} test;


链表的头节点(用于存放一个链表的逻辑头,由于链表是双向,每个节点都是头):

//declare a node for head of list .
#define LIST_HEAD(name) \
	Y_LISTHEAD name = LIST_HEAD_INIT(name)

LIST_HEAD(test_list); //声明了一个Y_LISTHEAD类型 test_list 变量,存放逻辑头

这里为了展示例子,我申请了几个变量:

test* ptr_test;
Y_LISTHEAD * pos;
test * entry;

为节点申请内存,并赋值

ptr_test = (test *)malloc(sizeof(test));
ptr_test->a = 0;

现在节点创建完毕,开始加入到链表

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_add(Y_LISTHEAD *new,
                  Y_LISTHEAD *prev,
                  Y_LISTHEAD *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}

/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(Y_LISTHEAD *new, Y_LISTHEAD *head)
{
    __list_add(new, head, head->next);
}

LIST_ADD(&ptr_test->list,&test_list);


同理,在添加几个。(详情见末尾例子)

然后,遍历链表并输出:


这里解释一下 GET_ENTRY()宏函数
//caculate offset-value about member to start of the struct 
//计算结构体地址和结构体某成员的地址差值,也就是偏移值
#define OFFSET(type, member) ((unsigned int) &((type *)0)->member)

//第一行声明了一个结构体元素类型的指针

 
//第二行通过偏移值计算结构体地址,这样就可以得到结构体内所有元素的值
//第三个参数member 为节点元素中,链表变量名
//第二个参数为节点元素类型名
#define GET_ENTRY(ptr, type, member) \
({   				\
    const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
    (type *)( (char *)__mptr - OFFSET(type,member) );		\
})
/**
 * list_for_each iterate over a list
 * @pos:the &struct list_head to use as a loop cursor.
 * @head:the head for your list.
 */
#define LIST_FOR_EACH(pos, head) \
<span style="white-space:pre">	</span>for (pos = (head)->next; pos != (head); pos = pos->next)
LIST_FOR_EACH(pos,&test_list){
		
	entry = GET_ENTRY(pos,test,list);	
	printf("%d\n",entry->a);
}


同理, LIST_DEL_ENTRY()之类的宏定义都是同样的实现。


实例:

list_test.c

/*
*	FileName:list_test.c
*	Version: 1.0
*	Description: The file test my list if it is right
*	Created On:2016-5-15
*	Modified date:
*	Author:Sky
*
*/
#include <stdio.h>
#include "Y_List/Y_List.h"

typedef struct {
	int a;
	Y_LISTHEAD list;
} test;

test* ptr_test;

int main(int argc, char * argv[]){
	
	//test head;

	LIST_HEAD(test_list);
	Y_LISTHEAD * pos;
	test * entry;
	
	//INIT_LIST_HEAD(head->list);
	
	
	ptr_test = (test *)malloc(sizeof(test));
	ptr_test->a = 0;
	
	LIST_ADD(&ptr_test->list,&test_list);

	ptr_test = (test *)malloc(sizeof(test));
	ptr_test->a = 2;
	
	LIST_ADD_TAIL(&ptr_test->list,&test_list);

	ptr_test = (test *)malloc(sizeof(test));
	ptr_test->a = 4;
	
	LIST_ADD(&ptr_test->list,&test_list);

	ptr_test = (test *)malloc(sizeof(test));
	ptr_test->a = 8;
	
	LIST_ADD_TAIL(&ptr_test->list,&test_list);


	LIST_FOR_EACH(pos,&test_list){
		
		entry = GET_ENTRY(pos,test,list);	
		printf("%d\n",entry->a);
	}


	LIST_DEL_ENTRY(&(ptr_test->list));


	LIST_FOR_EACH(pos,&test_list){
		
		entry = GET_ENTRY(pos,test,list);	
		printf("%d\n",entry->a);
	}

	
	LIST_FOR_EACH(pos,&test_list){
		
		entry = GET_ENTRY(pos,test,list);
		free(entry);
	}


	return 0;
}






LIST_ADD在给出地址后添加一个元素
LIST_ADD_TAIL在给出地址前添加一个元素
LIST_DEL_ENTRY删除指定地址的节点

 
 

运行截图:




其实链表只有几个部分要主要:

链表结构体

节点结构体

链表头

链表增删改查


而在Linux的链表实现中,要注意下面这个东西,怎么确定的节点结构体地址,这是


LInux链表实现的核心。搞清楚了这个,Linux链表你就会了

GET_ENTRY()


如果希望查看上面项目代码,移步:

https://github.com/flyinskyin2013/Y_LINUX_FRAME/tree/master/include/Y_List


#PS:请尊重原创,不喜勿喷


#PS:要转载请注明出处,本人版权所有


有问题请留言,看到后我会第一时间回复


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值