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)实例串联起来时,就需要在结构体内声明指向下一实例的指针,构成所谓的& ...
随机推荐
- [ES6] 17. Set
Es6 provides "Set", it likes array but the data inside should be unqiue. "Set" i ...
- [连载]JavaScript讲义(04)--- 函数和闭包
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2ZydWVk/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- Swift3.0语法变化
写在前面 首先和大家分享一下学习新语法的技巧:用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Syntax- 让Xcod ...
- 打开Excel时提示"您尝试打开的文件**.xls的格式与文件扩展名指定的格式不一致"
问题描述: 系统安装了WPS时,Analyzer导出excel时候,会提示"您尝试打开的文件**.xls的格式与文件扩展名指定的格式不一致",这是Excel的安全问题, ...
- Spirng_Batch
一.需求分析 使用Spring Batch对XML文件进行读写操作: 从一个xml文件中读取商品信息, 经过简单的处理, 写入另外一个xml文件中. 二.代码实现 1. 代码结构图: 2. appli ...
- E - 最短的名字
Description 在一个奇怪的村子中,很多人的名字都很长,比如aaaaa, bbb and abababab. 名字这么长,叫全名显然起来很不方便.所以村民之间一般只叫名字的前缀.比如叫'aaa ...
- HTML+CSS实例——漂亮的背景(一)
一.网址:http://www.csszengarden.com/?cssfile=213/213.css 二.效果 三.CSS body { background-color:#F0ECD6; ba ...
- InvocationTargetException
在使用反射的适合,调用的方法无论抛出什么异常,都会变成InvocationTargetException,要想得到原始的异常,必须使用getTargetException()
- rpm命令使用说明
RPM是RedHat Package Manager(RedHat软件包管理工具)类似Windows里面的“添加/删除程序” rpm 执行安装包二进制包(Binary)以及源代码包(Source)两种 ...
- 通过使用精简客户端,且不需要安装的客户端,配合PLSQL连接oracle数据库
通过使用精简客户端,且不需要安装的客户端,配合PLSQL连接oracle数据库. 首先下载安装包在Oralce官方网站上下载Oracle Instantclient Basic package.地址如 ...