Linux 内核 链表 的简单模拟(2)
第五章:Linux内核链表的遍历
/**
* 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)
这是遍历链表的一个方法,其实就是一个for循环的宏啦!写得很清楚。但是这些操作的还是struct list_head,跟我要的结构体没有半毛钱关系,怎么办?继续看:
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
这个就是由我们自定义的结构体中包含的struct list_head获得结构体的方式,其实就是上一篇博客的container_of的第二个名字啦!container_of到了这山沟里就换了一个很土的名字啦!
好了,下面看代码就一清二楚了:
struct list_head *p; //pointer to each struct list_head
struct Book *pb; //pointer to struct Book list_for_each(p,&MyBkList)
{
pb = list_entry(p, struct Book,list);
cout << pb->bkId << " " << pb->bkName << endl;
}
输出:

#include <string> using std::string; /*ÁޱíœÚµã*/
struct list_head {
struct list_head *next, *prev;
}; /*±íÊŸÊéµÄœá¹¹Ìå*/
struct Book
{
int bkId;
string bkName;
struct list_head list; //ËùÓеÄBookœá¹¹ÌåÐγÉÁޱí
}; /*³õÊŒ»¯Áޱí*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
} /*
* 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(struct list_head * new1,struct list_head * prev,struct list_head * next)
{
next->prev = new1;
new1->next = next;
new1->prev = prev;
prev->next = new1;
} /**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head->prev, head);
} /**
* 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(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head, head->next);
} /**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *))->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(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_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member) /**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member) /**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_struct within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member) /**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_next_entry(pos, member)) #undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
至此源代码myList.h
#include <iostream>
#include "myList.h" using namespace std; int main(void)
{
struct list_head MyBkList; //ŽŽœšÎÒµÄÁޱíÍ·
INIT_LIST_HEAD(&MyBkList); //³õÊŒ»¯ÕâžöÁޱí /*ŽŽœšÐÂÊéœá¹¹Ìå*/
struct Book bk1;
bk1.bkId = ;
bk1.bkName = "book1"; list_add_tail(&bk1.list, &MyBkList); //°ÑÐÂÊé1ŒÓµœÍ·œáµãMyBkListºóÃæ struct Book bk2;
bk2.bkId = ;
bk2.bkName = "book2"; list_add_tail(&bk2.list,&MyBkList); //°ÑÊé2ŒÓµœbk1ÓëMyBkListÖ®Œä£¬°ÑMyBkList¿Ž×öÍ·£¬ÔòΪMyBkList->bk1->bk2(°ŽÕ՜ڵãnextÖžÕ룬MyBkListµÄnextÖžÕëÊÇûÓбäµÄ£¬MyBkListµÄprevÖžÕë±äÁË) struct Book bk3 = { , "book3" };
list_add(&bk3.list, &MyBkList); //°ÑÊé3ŒÓµœheadÖ®ºó£¬ŒŽheadµÄnextÖžÕë struct list_head *p; //pointer to each struct list_head
struct Book *pb; //pointer to struct Book list_for_each(p,&MyBkList)
{
pb = list_entry(p, struct Book,list);
cout << pb->bkId << " " << pb->bkName << endl;
} /*
list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
}*/ cin.get();
}
至此源代码main.cpp
还有一个人更漂亮的遍历函数list_for_each_entry:
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member) /**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_struct within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member) /**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_next_entry(pos, member))
使用起来更好看:
struct Book *pb; //pointer to struct Book
list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
}
当然还有反向遍历等,就不多赘述了。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第六章:Linux内核链表删除
先来看看这个基本的删除节点的函数,这是其他删除函数的基础。其实这个删除函数和添加节点到链表的函数是对应的,添加的基本函数不也是以前后指针为参数并把节点添加到中间吗?Linux内核就是帅!
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
下面看调用上面函数的函数,其实list_del()是最常用的函数了,其他函数也只是铺垫:
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
#ifndef CONFIG_DEBUG_LIST
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
} static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
#else
extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif
其中,LIST_POISON1、LIST_POISON2 在我的M:\linux-3.14.5\include\linux下poison.h文件中:
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
/*
* Architectures might want to move the poison pointer offset
* into some well-recognized area such as 0xdead000000000000,
* that is also not mappable by user-space exploits:
*/
#ifdef CONFIG_ILLEGAL_POINTER_VALUE
# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
#else
# define POISON_POINTER_DELTA
#endif
上面的一些宏定义作用是:调用 __list_del_entry(struct list_head *entry)删除一个给定节点,这个函数会调用__list_del(struct list_head * prev, struct list_head * next),这样使得待删除的节点的前后节点因为正确连到链表里面而没有了问题了,但是待删除节点还是的结构体还是在的,其实并没有删除它,只是把它从链表里面踢出去了。为了防止意外访问到这个节点的前后节点(因为它已经不在链表中了)而出错,就给它的前后指针赋了一个非空但访问会引起页面错误的指针,表明小心中毒哦!
目前为止代码如下:
#include <iostream>
#include "myList.h" using namespace std; int main(void)
{
struct list_head MyBkList; //ŽŽœšÎÒµÄÁޱíÍ·
INIT_LIST_HEAD(&MyBkList); //³õÊŒ»¯ÕâžöÁޱí /*ŽŽœšÐÂÊéœá¹¹Ìå*/
struct Book bk1;
bk1.bkId = ;
bk1.bkName = "book1"; list_add_tail(&bk1.list, &MyBkList); //°ÑÐÂÊé1ŒÓµœÍ·œáµãMyBkListºóÃæ struct Book bk2;
bk2.bkId = ;
bk2.bkName = "book2"; list_add_tail(&bk2.list,&MyBkList); //°ÑÊé2ŒÓµœbk1ÓëMyBkListÖ®Œä£¬°ÑMyBkList¿Ž×öÍ·£¬ÔòΪMyBkList->bk1->bk2(°ŽÕ՜ڵãnextÖžÕ룬MyBkListµÄnextÖžÕëÊÇûÓбäµÄ£¬MyBkListµÄprevÖžÕë±äÁË) struct Book bk3 = { , "book3" };
list_add(&bk3.list, &MyBkList); //°ÑÊé3ŒÓµœheadÖ®ºó£¬ŒŽheadµÄnextÖžÕë struct list_head *p; //pointer to each struct list_head /*
list_for_each(p,&MyBkList)
{
pb = list_entry(p, struct Book,list);
cout << pb->bkId << " " << pb->bkName << endl;
}*/ struct Book *pb; //pointer to struct Book
list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
} cout<<"------------------------------------"<<endl; struct Book bk4={,"book4"};
list_add_tail(&bk4.list,&MyBkList); list_del(&bk3.list); list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
} cin.get();
}
main.cpp
#include <string> /*
* Architectures might want to move the poison pointer offset
* into some well-recognized area such as 0xdead000000000000,
* that is also not mappable by user-space exploits:
*/
#ifdef CONFIG_ILLEGAL_POINTER_VALUE
# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
#else
# define POISON_POINTER_DELTA
#endif /*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) using std::string; /*ÁޱíœÚµã*/
struct list_head {
struct list_head *next, *prev;
}; /*±íÊŸÊéµÄœá¹¹Ìå*/
struct Book
{
int bkId;
string bkName;
struct list_head list; //ËùÓеÄBookœá¹¹ÌåÐγÉÁޱí
}; /*³õÊŒ»¯Áޱí*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
} /*
* 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(struct list_head * new1,struct list_head * prev,struct list_head * next)
{
next->prev = new1;
new1->next = next;
new1->prev = prev;
prev->next = new1;
} /**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head->prev, head);
} /**
* 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(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head, head->next);
} /**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *))->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(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_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member) /**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member) /**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_struct within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member) /**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_next_entry(pos, member)) /*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
} /**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/ static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
} static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (struct list_head *)LIST_POISON1; //Linux kernel source does not have (struct list_head *)
entry->prev = (struct list_head *)LIST_POISON2;
} #undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
myList.h
到这里已经简单模拟实现了Linux内核链表最最基本的功能,还有其他功能,有兴趣的直接上源代码!
Linux 内核 链表 的简单模拟(2)的更多相关文章
- Linux 内核 链表 的简单模拟(1)
第零章:扯扯淡 出一个有意思的题目:用一个宏定义FIND求一个结构体struct里某个变量相对struc的编移量,如 struct student { int a; //FIND(struct stu ...
- C语言 Linux内核链表(企业级链表)
//Linux内核链表(企业级链表) #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> ...
- 深入分析 Linux 内核链表--转
引用地址:http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/index.html 一. 链表数据结构简介 链表是一种常用的组织有序数据 ...
- linux内核链表分析
一.常用的链表和内核链表的区别 1.1 常规链表结构 通常链表数据结构至少应包含两个域:数据域和指针域,数据域用于存储数据,指针域用于建立与下一个节点的联系.按照指针域的组织以及各个节 ...
- 深入分析 Linux 内核链表
转载:http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/ 一. 链表数据结构简介 链表是一种常用的组织有序数据的数据结构,它通过指 ...
- Linux 内核链表实现和使用(一阴一阳,太极生两仪~)
0. 概述 学习使用一下 linux 内核链表,在实际开发中我们可以高效的使用该链表帮我们做点事, 链表是Linux 内核中常用的最普通的内建数据结构,链表是一种存放和操作可变数据元 素(常称为节点) ...
- Linux 内核链表的使用及深入分析【转】
转自:http://blog.csdn.net/BoArmy/article/details/8652776 1.内核链表和普通链表的区别 内核链表是一个双向链表,但是与普通的双向链表又有所区别.内核 ...
- 链表的艺术——Linux内核链表分析
引言: 链表是数据结构中的重要成员之中的一个.因为其结构简单且动态插入.删除节点用时少的长处,链表在开发中的应用场景许多.仅次于数组(越简单应用越广). 可是.正如其长处一样,链表的缺点也是显而易见的 ...
- Linux 内核链表 list.h 的使用
Linux 内核链表 list.h 的使用 C 语言本身并不自带集合(Collection)工具,当我们需要把结构体(struct)实例串联起来时,就需要在结构体内声明指向下一实例的指针,构成所谓的& ...
随机推荐
- Binder机制1---Binder原理介绍
1.Binder通信机制介绍 这篇文章会先对照Binder机制与Linux的通信机制的区别,了解为什么Android会另起炉灶,採用Binder.接着,会依据Binder的机制,去理解什么是Servi ...
- UVA 1401 - Remember the Word(Trie+DP)
UVA 1401 - Remember the Word [题目链接] 题意:给定一些单词.和一个长串.问这个长串拆分成已有单词,能拆分成几种方式 思路:Trie,先把单词建成Trie.然后进行dp. ...
- [原创]如何写好SqlHelper 之终章
精简的美丽...... 标题有点大.但是,我觉得99%的接近了. 好了,下面我们来说说一个SqlHelper为了适应各种不同的业务需要,它应该具备哪些基本要素. 第一点.可控的事务. 事务是数据库操作 ...
- 把json格式对象转成可提交字符串格式,会过滤掉函数 {a: {b: 3}, b: [1], c: "d"} -> a.b=3&b[0]=1&c=d
var json = { name: "任务名称" , scoreRule: "", score: "", // 如果规则表达式不为空,则默 ...
- Ruby on Rails Tutorial 第二章 之 用户资源&MVC&REST
说明:用户资源包括用户数据模型和这个模型相关的Web页面. 1.用户数据模型如下: 2.使用Rails内置的脚手架生成用户资源中,执行如下所示命令: $ rails generate scaffold ...
- Apache Shiro Architecture--官方文档
原文地址:http://shiro.apache.org/architecture.html Apache Shiro's design goals are to simplify applicati ...
- eclipse 的小技巧
1. ctrl+o:快速outline 如果想要查看当前类的方法或某个特定方法,但又不想把代码拉上拉下,也不想使用查找功能的话,就用ctrl+o吧.它可以列出当前类中的所有方法及属性,你只需输入你想要 ...
- Java基础知识强化之集合框架笔记75:哈希表
1. 哈希表数据结构(数组): 2. 哈希表确定元素是否相同: (1)判断的是两个元素的哈希值是否相同 如果相同,再判断两个对象内容是否相同 (2)判断哈希值相 ...
- Android(java)学习笔记89:泛型概述和基本使用
package cn.itcast_01; import java.util.ArrayList; import java.util.Iterator; /* * ArrayList存储字符串并遍历 ...
- html/css 两个div在同一行
在界面设计的时候,经常需要将两个div在同一行显示. 但是每次都会忘记怎么做,特此随笔,备忘. 如以下要将“第一个div”和“第二个div”显示在同一行: <div id="id1&q ...