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)实例串联起来时,就需要在结构体内声明指向下一实例的指针,构成所谓的& ...
随机推荐
- Html页中使用OCX控件
原文:http://blog.csdn.net/mouse8166/article/details/5515657 最近准备开发一个b/s架构的应用程序需要用到activeX控件,web服务器尚未进入 ...
- IOS 常用第三方库
名称 特性 效果图 FXBlurView 实时背景模糊效果 FDFullscreenPopGesture 让UINavigationController在屏幕任何位置均可滑动返回 NJKWebVi ...
- thinkphp模板中使用自定义函数
注意:自定义函数要放在项目应用目录/common/common.php中. 这里是关键. 模板变量的函数调用格式:{$varname|function1|function2=arg1,arg2,### ...
- ios开发——实用技术篇OC篇&获取内存使用情况
获取内存使用情况 iOS 获取 当前设备 可用内存 及当前 应用 所占内存 (-- ::) 转载 ▼ 标签: ios 设备 可用内存 所占内存 内存 it 分类: iOS // 获取当前设备可用内存及 ...
- flash 入门课知识小结
一. 几种类型帧的小结:(关键帧.空白关键帧.普通帧)1. 特点 帧——是进行flash动画制作的最基本的单位,每一个精彩的flash动画都是由很多个精心雕琢的帧构成的,在时间轴上的每一帧都可以包含 ...
- 琐碎-将hadoop源码作为工程导入eclipse
之前写过如何用eclipse看hadoop源码,虽然非官方版的,但是可以达到目的,最重要是简单方便快速 官方版(hadoop2.2.0)的也有: 源码目录为: 和之前的源码目录有很大的不同 编译的时候 ...
- poj 3252 Round Numbers 【推导·排列组合】
以sample为例子 [2,12]区间的RoundNumbers(简称RN)个数:Rn[2,12]=Rn[0,12]-Rn[0,1] 即:Rn[start,finish]=Rn[0,finish]-R ...
- PHP读书笔记(3)-常量
什么是常量 什么是常量?常量可以理解为值不变的量 :或者是常量值被定义后,在脚本的其他任何地方都不可以被改变.手册上是这么定义PHP的常量:常量是一个简单值的标识符(名字).如同其名称所暗示的,在脚本 ...
- json2使用方法
例子1: //直接声明json数据结构 var myJSONObject = {"bindings": [ {"ircEvent": "PRIVMSG ...
- java中的静态方法
静态方法是属于类的,内存必须为它分配内存空间,这个空间一直由静态方法占用,内存管理器不会由于静态方法没有被调用而将静态方法的存储空间收回,这样如果将所有的方法都声明为静态方法,就会占用大量的内存空间, ...