LinuxKernel 入侵式双向链表的设计,分析,使用
PS:要转载请注明出处,本人版权所有。
PS: 这个只是基于《我自己》的理解,
如果和你的原则及想法相冲突,请谅解,勿喷。
前置说明
本文作为本人csdn blog的主站的备份。(BlogID=020)
本文发布于 2016-06-06 14:49:11,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=020)
环境说明
无
前言
无
入侵式链表
链表按照实现原理我分为两类,一是普通的链表,二是入侵式链表。(区别就是,链表结构体里面有没有数据)。由于我重写了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)
这里为了展示例子,我申请了几个变量:
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) \
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: 要转载请注明出处,本人版权所有。
PS: 有问题请留言,看到后我会第一时间回复。
LinuxKernel 入侵式双向链表的设计,分析,使用的更多相关文章
- [课程设计]Scrum 2.5 多鱼点餐系统开发进度(下单一览页面-菜式添加框架设计)
Scrum 2.5 多鱼点餐系统开发进度 (下单一览页面-菜式添加框架设计) 1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题 ...
- 60个响应式的Web设计教程–能够手机访问!
想要学习响应式[responsive:屏幕自适应的效果]的网页设计和开发技术?在这个超大的收藏集合中,我想你定会找到想要开始学习的响应式网页设计教程. 面对超过1亿的手机互联网用户,开发专业和用户友好 ...
- 微信小程序 - 非入侵式布局
非入侵式布局,就是不影响原有内容以及代码,增加用户体验感(UE)的一种方式. 例如我们每个接口必须返回: 0:请求成功 -1:请求失败 .... 这样就便于前端判断数据是否加载成功,然后以客观的方式提 ...
- angular学习笔记(六)-非入侵式javascript
这篇主要讲解非入侵式javascript. 在传统的前端开发中,把js写在html中,称为入侵式的javascript: <span id="select_area" onc ...
- 响应式web网站设计制作方法
在研究响应式的时候,记录了一些感想,分享出来,抛砖引玉,希望可以和大家一起讨论.总结下来,响应式比之前想象的要复杂得多.1. ie9以下(不包括ie9)采用ie条件注释,为ie8以及一下单独开一个样式 ...
- 响应式web布局设计实战总结教程
响应性web设计的理念是:页面的设计与开发应当根据用户行为与设备环境(包括系统平台,屏幕尺寸,屏幕定向等)进行相应的响应及调整.具体的实践方式由多方面组成,包括弹性网格和布局,图片,css Media ...
- 通用双向链表的设计(参考Linux系统中的实现)
通常我们设计设计链表都是将数据域放在里面,这样每次需要使用链表的时候都需要实现一个链表,然后重新实现它的相关操作,这里参考Linux系统中的设计实现了一个通用的双向链表,只需要在你的结构里面有一个这个 ...
- Javascript 链式运动框架——逐行分析代码,让你轻松了解运动的原理
所谓链式运动,就是一环扣一环.我们的很多运动实际上来说指的就是分阶段的,第一个阶段动完,下个阶段开始动. 这个链式运动框架就是用来处理这些问题的. 我们先来看下之前的运动框架,以下是Javascrip ...
- 【C/C++】关于隐式转换·面试题分析
题目 以下两个程序片段A 和B ,问哪个能进入循环? 片段A: unsigned short i; unsigned ; ; i < index-; i++) { ........ } 片段B: ...
- 又一起.NET程序挂死, 用 Windbg 抽丝剥茧式的真实案例分析
一:背景 1. 讲故事 前天有位粉丝朋友在后台留言让我帮忙看看他的 Winform程序 UI无响应 + 410线程 到底是啥情况,如下图: 说实话,能看到这些真实案例我是特别喜欢的 ,就像医生看病,光 ...
随机推荐
- 蓝鲸:主机频繁提示“You have new mail in /var/spool/mail/root” 定位解决
前些天安装蓝鲸的测试环境频繁出现You have new mail in /var/spool/mail/root,查看发现是/usr/local/gse/agent/bin/gsectl: line ...
- MYSQL-另一种行转列的实现方式
行转列的实现方式:使用mysql.help_topic --行转列 SELECT b.help_topic_id, substring_index( a.levels, ',', b.help_top ...
- 盘点Java集合(容器)概览,Collection和Map在开发中谁用的最多?
写在开头 在Java的世界里万物皆对象.但我认为是万物皆数据,世界由各种各样数据构建起来,我们通过程序去实现数据的增删改查.转入转出.加减乘除等等,不同语言的实现方式殊途同归.由此可见,数据对于程序语 ...
- JOISC 2018 记录
Day1 T1 Construction of Highway 每一次操作形如查询一条到根的链上的逆序对数,然后将这条链的权值全部修改成同一个权值. 发现这个操作类似于 LCT 的 Access 操作 ...
- c# 代码操作ftp服务器文件
好久不见,我又回来了.给大家分享一个最近c#代码操作ftp服务器的代码示例 1 public abstract class FtpOperation 2 { 3 /// <summary> ...
- Java I/O 教程(一) 介绍
Java I/O (Input and Output) 用于处理输入和输出 Java利用流的手段来加快I/O操作.java.io包中包含了各种支持输入输出操作的类.参考下图: 我们可以利用java i ...
- Java集合框架学习(一)介绍
介绍 Java集合框架是一组接口和类的集合,它使得存储和处理数据更加有效率. 该框架有一些类,有很多函数使得程序员更加容易的处理集合类型数据. 后面的教程就是针对这些常用类展开,配合例子代码来给大家一 ...
- leetcode - 中序遍历
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 . 示例 1: 输入:root = [1,null,2,3] 输出:[1,3,2] 示例 2: 输入:root = [] 输出:[] 示例 ...
- 以二进制文件安装K8S之部署Node服务
概述 在Node上需要部署Docker.kubelet.kube-proxy,在成功加入Kubernetes集群后,还需要部署CNI网络插件.DNS插件等管理组件. 本节以将192.168.3.138 ...
- 项目实战:Qt+Android模拟操作器(模拟操作app,打开,点击,输入,获取验证码等等)
若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/109313803各位读者,知识无穷而人力有穷,要 ...