原文地址:http://www.cnblogs.com/bastard/archive/2012/10/19/2731107.html

通常实现双向链表的数据结构:

struct list_node1{
struct list_node1 *next,*prev;
type1 m1;
type2 m2;
};
struct list_node2{
struct list_node2 *next,*prev;
type1 m1;
type2 m2;
};
……

对于每一种数据结构都定义了其特定的实现链表的结构和对应的方法(add/del)操作链表;

  但对于具有大量不同数据结构,都要使用链表的系统中,如果为每一种数据结构定义特定的结构,和操作方法,

无疑使代码变得重复和臃肿,需要实现一种通用的双向链表方法,对各种数据结构都能适用。

  C语言中又没有C++里面的模板,该如何实现呢?

linux内核中大量使用如下数据结构实现双向链表:

struct list_head {
struct list_head *next, *prev;
};

  如果需要有某种数据结构的双向队列,就在这种结构内部放一个list_head数据结构成员。

struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
}

形成了如下结构:

    

如何通过kobject 链表结构中的 list_head 成员entry访问下一个成员呢?

系统提供了宏list_entry:

#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

//访问链表成员
kobject *obj = objList;
kobject *nextObj = (kobject *)list_entry(obj->entry->next,struct kobject,entry);

这个list_entry是什么道理呢:

  ptr:是指向当前kobject结构对象中的数据成员entry,(char *)(ptr):entry成员地址 ——AddrA

  (unsigned long)(&((type *)0)->member)):将地址0转化为类型为type(struct kobject )对象,取member(entry)成员的地址——AddrB

  (type *)(AddrA - AddrB):得到kobject结构对象的首地址,转化为kobject对象。

  这里需要关注的就是AddrB:将地址0转化为类型为type(struct kobject )对象,取member(entry)成员的地址。

    表示当struct kobject 对象首地址为0时,得到成员member(entry)的地址,相对首地址的偏移地址。

    通过struct kobject 对象中member(entry)的地址 ,以及相对首地址的偏移量,就能计算出struct kobject 对象的首地址。

如下结构:

    

  充分利用了C语言中直接操作内存地址的特性。

 

 
 

Linux利用list_head结构实现双向链表的更多相关文章

  1. Linux 内核list_head 学习

    Linux 内核list_head 学习(一) http://www.cnblogs.com/zhuyp1015/archive/2012/06/02/2532240.html 在Linux内核中,提 ...

  2. [转载]Linux 内核list_head 学习(一)

    在Linux内核中,提供了一个用来创建双向循环链表的结构 list_head.虽然linux内核是用C语言写的,但是list_head的引入,使得内核数据结构也可以拥有面向对象的特性,通过使用操作li ...

  3. Linux内核kobject结构体分析

    1.前言 Linux内核中有大量的驱动,而这些驱动往往具有类似的结构,根据面向对象的思想,可以将共同的部分提取为父类,而这个父类就是kobject,kobject结构体中包含了大量设备的必须信息,而三 ...

  4. Linux常用目录结构

    此文引用自51CTO博客,博主snail_hf,原文地址<Linux系统目录详解(全而易懂)> 目录结构 / 根目录,处于Linux系统树形结构的最顶端,它是Linux文件系统的入口,所有 ...

  5. [转载]Linux内核list_head学习(二)

    前一篇文章讨论了list_head 结构的基本结构和实现原理,本文主要介绍一下实例代码. 自己如果想在应用程序中使用list_head 的相应操作(当然应该没人使用了,C++ STL提供了list 用 ...

  6. (第五篇)Linux操作系统基本结构介绍

    Linux操作系统基本结构介绍 Linux系统一般有4个主要部分:内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使用 ...

  7. (一)Linux之目录结构

    Linux之目录结构 目录 Linux之目录结构 一.概述 一.基本介绍 二.具体的目录结构(不用背,知道即可) Linux /usr目录 Linux /var 目录 一.概述 学习 Linux,不仅 ...

  8. Linux内核--链表结构(一)

    一.前言 Linux内核链表结构是一种双向循环链表结构,与传统的链表结构不同,Linux内核链表结构仅包含前驱和后继指针,不包含数据域.使用链表结构,仅需在结构体成员中包含list_head*成员就行 ...

  9. Linux 利用进程打开的文件描述符(/proc)恢复被误删文件

    Linux 利用进程打开的文件描述符(/proc)恢复被误删文件 在 windows 上删除文件时,如果文件还在使用中,会提示一个错误:但是在 linux 上删除文件时,无论文件是否在使用中,甚至是还 ...

随机推荐

  1. jmeter的基本使用过程

    jmeter的基本使用过程 接下来几周,我将通过视频的方式,录制下来jmeter的基本用法,方便大家参考学习 可能导图会随时调整

  2. 解决:Unable to execute dex: GC overhead limit exceeded

    转自http://blog.sina.com.cn/s/blog_6e334dc70101hnug.html Android打包时下面的错误: Unable to execute dex: GC ov ...

  3. 最大流——EK算法

    一.算法理论 [基本思想] 反复寻找源点s到汇点t之间的增广路径,若有,找出增广路径上每一段[容量-流量]的最小值delta,若无,则结束.在寻找增广路径时,可以用BFS来找,并且更新残留网络的值(涉 ...

  4. servlet入门(1)

    第一个servlet类 1.编写一个java类,继承HttpServlet类 2.重写doget和dopost方法 3.Servlet程序在tomcat服务器运行 第一步:找到server窗口,并新建 ...

  5. CodeForces Round #521 (Div.3) D. Cutting Out

    http://codeforces.com/contest/1077/problem/D You are given an array ss consisting of nn integers. Yo ...

  6. CentOS7中rpm,yum软件安装命令

    RPM包常用安装位置说明 /etc/                   配置文件安装目录 /usr/bin/               可执行的命令安装目录 /usr/lib/           ...

  7. elementUI中的el-form怎么使用正则进行验证

    http://element.eleme.io/#/zh-CN/component/form里给出了一个form验证的例子,但是都是使用el-form带有的验证规则,怎么使用自己定义的规则进行验证呢? ...

  8. [STL] 遍历删除两个vector中交集

    #include <vector> #include <string> #include <algorithm> using namespace std; int ...

  9. 【C++ 拾遗】Function-like Macros

    Macro expansion is done by the C preprocessor at the beginning of compilation. The C preprocessor is ...

  10. C++——派生类中的访问——可见性问题

    C++中派生类对基类成员的访问形式主要有以下两种: 1.内部访问:由派生类中新增成员对基类继承来的成员的访问. 2.对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问.今天给大家介绍在 ...