Android中的双向链表「建议收藏」

Android中的双向链表

大家好,又见面了,我是全栈君。

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;
}


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115628.html原文链接:https://javaforall.net

(0)
上一篇 2022年2月1日 下午8:00
下一篇 2022年2月1日 下午8:00


相关推荐

  • JavaScript稀疏数组

    JavaScript稀疏数组稀疏数组就是包含从 0 开始的不连续索引的数组 以下 a 和 c 都为稀疏数组 虽然数组存在长度 但数组单元并不存在 nbsp vara newArray 3 a undefined 3 varb undefined undefined undefined b undefined undefined undefined varc c length 3 c

    2026年3月20日
    2
  • IntelliJ IDEA 2021.1 x64激活码破解方法

    IntelliJ IDEA 2021.1 x64激活码破解方法,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月15日
    297
  • CUDA、CUDNN在windows下的安装及配置

    CUDA、CUDNN在windows下的安装及配置参考文章全网最详细|Windows安装TensorFlow2.0GPU详细教程Wind10安装anaonda+cuda10.1+cudnn+pytorch+tensorflow-gpuwin10+GTX1050Ti+anaconda3+tensorflow1.14.0+cuda10.0+cudnn7.6.1.34(带GPU使用检测)一、安装前的准备(1)查看自己N卡…

    2022年6月14日
    45
  • html鼠标手状态,css鼠标样式cursor介绍(鼠标手型)

    html鼠标手状态,css鼠标样式cursor介绍(鼠标手型)CSS鼠标样式语法如下:任意标签中插入style=”cursor:*”例子:文本或其它页面元素文本或其它页面元素注意把*换成如下15个效果的一种:下面是对这15种效果的解释。移动鼠标到解释上面,看看你的鼠标起了什么变化吧!hand是手型例子:CSS鼠标手型效果CSS鼠标手型效果pointer也是手型,这里推荐使用这种,因为这可以在多种浏览器下使用。例子:CSS鼠标手型效果CS…

    2022年5月6日
    60
  • 知识图谱入门 (七) 知识推理

    知识图谱入门 (七) 知识推理欢迎大家关注我的博客http://pelhans.com/,所有文章都会第一时间发布在那里哦~本节对本体任务推理做一个简单的介绍,并介绍本体推理任务的分类。而后对本体推理的方法和工具做一个介绍。知识推理简介知识推理任务分类所谓推理就是通过各种方法获取新的知识或者结论,这些知识和结论满足语义。其具体任务可分为可满足性(satisfiability)、分类(clas…

    2022年6月12日
    30
  • c语言 bzero,bzero, memset ,setmem 区别(示例代码)

    c语言 bzero,bzero, memset ,setmem 区别(示例代码)bzero 原型 externvoidbz void s intn 用法 include 功能 置字节字符串 s 的前 n 个字节为零 说明 bzero 无返回值 举例 bzero c include includeintma struct inta chars 5 floatf tt chars 20 bzero amp tt sizeof t

    2026年3月18日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号