1.看源代码必须搞懂Android的数据结构。在init源代码中双向链表listnode使用非常多,它仅仅有prev和next两个指针,没有不论什么数据成员。这个和linux内核的list_head如出一辙,由此可见安卓深受linux内核的影响的。本来来分析一下这个listnode数据结构。

这里须要考虑的一个问题是,链表操作都是通过listnode进行的,但是那只是是个连接件。假设我们手上有个宿主结构,那当然知道了它的某个listnode在哪里,从而以此为參数调用list_add和list_del函数。但是,反过来。当我们顺着链表取得当中一项的listnode结构时,又如何找到其宿主结构呢?在listnode结构中并没有指向其宿主结构的指针啊。毕竟。我们我真正关心的是宿主结构。而不是连接件。对于这个问题,我们举例内核中的list_head的样例来解决。内核的page结构体含有list_head成员,问题是:知道list_head的地址。如何获取page宿主的地址?以下是取自mm/page_alloc.c中的一行代码:

page = memlist_entry(curr, struct page, list);

这里的memlist_entry将一个list_head指针curr换算成其宿主结构的起始地址,也就是取得指向其宿主page结构的指针。读者可能会对memlist_entry()的实现感到困惑。

#define memlist_entry list_entry

而list_entry定义则在include/linux/list.h中

135 /**
136 * list_entry get
the struct for this entry
137 * @ptr: the &struct list_head pointer.
138 * @type: the type of the struct this is embedded in.
139 * @member: the name of the list_struct within the struct.
140 */
141 #define list_entry(ptr, type, member) \
142 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

这样我们应该就明确了。curr是一个page结构内部成分list的地址,而我们所须要的却是那个page结构本身的地址,所以要从curr减去一个偏移量,即成分list在page内部的位移量。

那么这个位移量怎么求?&((struct page*)0)->list就表示当结构page正好在地址0上时其成分list的地址,这就是所求的偏移量。

2.測试代码

#include<stdio.h>
#include<stddef.h> typedef struct _listnode
{
struct _listnode *prev;
struct _listnode *next;
}listnode; #define node_to_item(node,container,member) \
(container*)(((char*)(node))-offsetof(container,member)) //向list双向链表尾部加入node节点,list始终指向双向链表的头部(这个头部仅仅含有prev/next)
void list_add_tail(listnode *list,listnode *node)
{
list->prev->next=node;
node->prev=list->prev;
node->next=list;
list->prev=node;
}
//定义一个測试的宿主结构
typedef struct _node
{
int data;
listnode list;
}node; int main()
{
node n1,n2,n3,*n;
listnode list,*p;
n1.data=1;
n2.data=2;
n3.data=3;
list.prev=&list;
list.next=&list;
list_add_tail(&list,&n1.list);
list_add_tail(&list,&n2.list);
list_add_tail(&list,&n3.list);
for(p=list.next;p!=&list;p=p->next)
{
n=node_to_item(p,node,list);
printf("%d\n",n->data);
}
return 0;
}

Android中的双向链表的更多相关文章

  1. Android中的数据结构

    数据结构在Android中也有着大量的运用,这里采用数据结构与源代码分析相结合,来认识Android的数据结构 线性表 线性表可分为顺序存储结构和链式存储结构 顺序存储结构-ArrayList 通过对 ...

  2. Android中的LruCache的原理和使用

    Android中的LruCache的原理和使用 LruCache,虽然很多文章都把LRU翻译成"最近最少使用"缓存策略,但Android中的LruCache真的如此吗? 答案是No ...

  3. Android中的LinearLayout布局

    LinearLayout : 线性布局 在一般情况下,当有很多控件需要在一个界面列出来时,我们就可以使用线性布局(LinearLayout)了,  线性布局是按照垂直方向(vertical)或水平方向 ...

  4. Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...

  5. Android中使用ExpandableListView实现微信通讯录界面(完善仿微信APP)

    之前的博文<Android中使用ExpandableListView实现好友分组>我简单介绍了使用ExpandableListView实现简单的好友分组功能,今天我们针对之前的所做的仿微信 ...

  6. Android中ListView实现图文并列并且自定义分割线(完善仿微信APP)

    昨天的(今天凌晨)的博文<Android中Fragment和ViewPager那点事儿>中,我们通过使用Fragment和ViewPager模仿实现了微信的布局框架.今天我们来通过使用Li ...

  7. Android中Fragment和ViewPager那点事儿(仿微信APP)

    在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...

  8. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  9. 【月入41万】Mono For Android中使用百度地图SDK

    借助于Mono For Android技术,.Net开发者也可以使用自己熟悉的C#语言以及.Net来开发Android应用.由于Mono For Android把Android SDK中绝大部分类库都 ...

随机推荐

  1. Codeforces 474F - Ant colony

    注意到每个区间生存下来的蚂蚁的长度等于区间的gcd 于是可以先预处理出区间的gcd 然后二分查找就好了 预处理gcd我这里用的是倍增法 总的时间复杂度O(NlogN) /* Cf 271F 倍增求区间 ...

  2. 关于使用iframe标签自适应高度的使用

    在ifrome内设定最小高度,(此方法只适用于页面内切换高度不一.但是会保留最大高度,返回后保持最大高度不再回到最初页面的高度) <iframe id="one4" widt ...

  3. WPF WebBrowser 不可见问题的解析[转]

    问题概述: 1.在Xaml中加入WebBrowser(不论是WPF中的控件,还是Winform中的控件) 2.设置Window Background="Transparent" A ...

  4. Node 之 Express 学习笔记 第二篇 Express 4x 骨架详解

    周末,没事就来公司加班继续研究一下Express ,这也许也是单身狗的生活吧. 1.目录结构: bin, 存放启动项目的脚本文件 node_modules, 项目所有依赖的库,以及存放 package ...

  5. Sublime text3 JS语法检测工具安装及使用

    Sublime text3 JS语法检测工具安装及使用 工具/原料 sublime text3 nodejs sublimeLinter sublimeLinter-jshint 方法/步骤 首先ct ...

  6. js 中的流程控制-条件语句

    条件语句: if(exp)执行一句代码 <script> var x = 1 ; if(x == 1 ) //当if判断语句结果是true 或者 false 当判断结果等于true的时候, ...

  7. MySQL zip版安装配置

    文章出处:http://www.cnblogs.com/winstic/,请保留此连接 这段时间在学习Python 数据库操作知识,简单整理MySQL zip文件安装方法 下载 在MySQL官网htt ...

  8. Binding在WPF中的使用

    闲来无事,不想打DOTA,在这里小小研究下wpf中关于Binding的东西. 咯咯 在我们印象中,Binding的意思是“绑定”,这个“绑”大概取自于Bind这个单词吧,这么理解的话就是以音译英了,没 ...

  9. uboot使用tftp下载时出现“checksum bad”问题原因分析

    一.问题 二.原因分析 你的虚拟机是不是这样设置的呢? 如果是的话,请看下边的解释: 使用NAT模式,就是让虚拟系统借助NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网.也就是说,使用NA ...

  10. 在Ubuntu12.0.4下搭建TFTP服务器

    一.安装相关安装包 tftpd(服务端),tftp(客户端) sudo apt-get install tftp-hpa tftpd-hpa 安装xinetd sudo apt-get install ...