zoukankan      html  css  js  c++  java
  • Linux源码 list.h解析

    Linux源码中include/linux/list.h封装了双向链表的数据结构。

    网上实现双向链表的方式大抵相同,都是定义一个struct Node表示链表的节点,Node结构体包含指向节点数据的指针,和指向节点的next和pre指针:

    1 struct Node {
    2    void *data;
    3    Node *next;
    4    Node *pre;   
    5 };

    这种方式将存放的数据保存在链表的节点内部,结构图如下:

    list.h的实现思路很有趣。上图中存放的数据(绿色部分),被Node节点封装,耦合度较高。存放的数据一定要保存在Node节点中,而且访问数据时需要经历一次Node *到Data *的跳转,可能会破坏cache,进行两次内存寻址。

    而在list.h中,将链表最基本的数据成员(next和pre指针)封装在list_head结构体中。

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

    存放数据的结构体只需要将list_head结构体引入,即可作为链表的节点:

    struct Data {
       ... // 存放的数据
       struct list_head list;  
    };

    这样数据即可脱离上个方式中Node的限制,只需要在结构体中存储next和pre指针即可作为链表的节点,达到解耦的目的。如下图(绿色部分是存储的数据):

    当然实现这种存储方式也要解决一个问题:如何通过next指针或pre指针获取数据?

    假设我们定义了以下结构体封装一个人的基本信息:

    struct people {
        char name[20];
        int age;
        struct list_head list;
    };
    
    struct people p1,p2 ;
    strcpy(p1.name, "Jack");
    p1.age = 20;
    strcpy(p2.name, "Judy");
    p2.age = 18;
    
    p1->pre = &p2;
    p1->next = &p2;
    p2->next = &p1;
    p2->pre = &p1;

    从p1开始遍历这个链表时,我们怎么获取p2的数据呢?

    首先,我们通过p1->next得到了p2中list_head成员的地址。但是无法获取p2其他成员变量的地址。

    list.h是通过offsetof和container_of宏来获取list_head的父结构体成员变量地址的:

    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    #define  container_of(ptr, type, member) ({    
              const typeof( ((type *)0)->member ) *__mptr = (ptr); 
              (type *)( (char *)__mptr - offsetof(type,member) );})

    offsetof:获取成员变量相对于结构体的偏移量

     如offsetof(struct people, age),展开为:((size_t)&((struct people *)0)->age)

    假设struct people的地址为0,那(struct people*)0->age的地址就是age相对于struct people的偏移量。

    container_of:给定指向成员变量member的指针ptr,获取父结构体的地址

    父结构体的地址其实就是 ptr - offsetof(TYPE, MEMBER)

    首先,定义一个__mptr=ptr,__mptr的类型为const typeof(((type *)0)->member) *

    再获取父结构体的地址:(type *) ((char *)__mptr = offsetof(type, number))

    在list.h中,定义了list_entry宏,以此通过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)
  • 相关阅读:
    使用 Markdown Flow 画流程图
    两串锂电池的电池匹配
    笔记: CC2540 和 CC2541 的区别
    Elasticsearch 5.x 关于term query和match query的认识
    es 批量导入文件
    mac 下搭建Elasticsearch 5.4.3分布式集群
    Elastic Search 5.4.3 java api 入门
    solr java demo 基础入门
    创建索引并进行查询
    RabbitMq 之简单队列
  • 原文地址:https://www.cnblogs.com/HadesBlog/p/14264933.html
Copyright © 2011-2022 走看看