openharmony内核中不一样的双向链表

不一样的双向链表

  • 链表初识别
  • 遍历双向链表
  • 参考链接

链表初识别

最近看openharmony的内核源码时看到一个有意思的双向链表,结构如下

typedef struct LOS_DL_LIST{
    struct LOS_DL_LIST *pstPrev; //前驱节点
    struct LOS_DL_LIST *pstNext; //后继节点
}LOS_DL_LIST;

不知道大家看上面的结构体有没有发现诡异的地方?
没错,这个双向链表咋没有数据呢???
其实LOS_DL_LIST不能单独拿来用,他需要放置于内容结构体上,如下图
在这里插入图片描述
现在有个任务,给你一个LOS_DL_LIST,如何获得内容结构体的首地址?
具体如何做,我们看看下面的两个宏,并结合实际的例子来进行分析

typedef unsigned long       UINTPTR;
//获取指定结构体内的成员相对于结构体起始地址的偏移量
#define LOS_OFF_SET_OF(type, member) ((UINTPTR)&((type *)0)->member)

//根据结构体成员地址、结构体类型、结构体成员名,推出结构体的首地址并强制转换
#define LOS_DL_LIST_ENTRY(item, type, member) \
    ((type *)((void*)((char*)(item) - LOS_OFF_SET_OF(type, member))))

LOS_OFF_SET_OF的用法可以看看我的这篇博客:c语言取结构体的偏移量

#include <iostream>
#include<string>
#include<string.h>
using namespace std;
typedef unsigned long       UINTPTR;

//获取指定结构体内的成员相对于结构体起始地址的偏移量
#define LOS_OFF_SET_OF(type, member) ((UINTPTR)&((type *)0)->member)

//根据结构体成员地址、结构体类型、结构体成员名,推出结构体的首地址并强制转换
#define LOS_DL_LIST_ENTRY(item, type, member) \
    ((type *)((void*)((char*)(item) - LOS_OFF_SET_OF(type, member))))

typedef struct LOS_DL_LIST{
    struct LOS_DL_LIST *pstPrev;
    struct LOS_DL_LIST *pstNext;
}LOS_DL_LIST;

//定义一个简单的结构体
typedef struct Book{
    char name[20];
    char author[20];
    double price;
    LOS_DL_LIST otherBook;

} Book;

//输出结构体信息
void print_book(Book *book){
    cout<<"书名:"<<book->name<<" ,作者:"<<book->author<<" ,价格:"<<book->price<<endl;
}

int main(){
    Book book = {"三国演义", "罗贯中",100.5};
    Book * book_ = LOS_DL_LIST_ENTRY(&book.otherBook,Book,otherBook);
    cout<<(book_ == &book)<<endl;
	print_book(&book);
    print_book(book_);
}

在这里插入图片描述

从上面的结果可以看出,使用LOS_DL_LIST_ENTRY也是可以获得内容结构体的首地址

遍历双向链表

直接看我写的demo吧

#include <iostream>
#include<string>
#include<string.h>
using namespace std;
typedef unsigned long       UINTPTR;

//获取指定结构体内的成员相对于结构体起始地址的偏移量
#define LOS_OFF_SET_OF(type, member) ((UINTPTR)&((type *)0)->member)

//根据结构体成员地址、结构体类型、结构体成员名,推出结构体的首地址并强制转换
#define LOS_DL_LIST_ENTRY(item, type, member) \
    ((type *)((void*)((char*)(item) - LOS_OFF_SET_OF(type, member))))

typedef struct LOS_DL_LIST{
    struct LOS_DL_LIST *pstPrev;
    struct LOS_DL_LIST *pstNext;
}LOS_DL_LIST;

//定义一个简单的结构体
typedef struct Book{
    char name[20];
    char author[20];
    double price;
    LOS_DL_LIST otherBook;

} Book;

//输出结构体信息
void print_book(Book *book){
    cout<<"书名:"<<book->name<<" ,作者:"<<book->author<<" ,价格:"<<book->price<<endl;
}
//头插法添加节点
void LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
{
    node->pstNext = list->pstNext;
    node->pstPrev = list;
    list->pstNext->pstPrev = node;
    list->pstNext = node;
}
//初始化头节点
void LOS_ListInit(LOS_DL_LIST *list)
{
    list->pstNext = list;
    list->pstPrev = list;
}

//定义一个节点并初始化为双向链表节点
#define LOS_DL_LIST_HEAD(list) LOS_DL_LIST list = { &(list), &(list) }





//获取双向链表中指定链表节点的下一个节点所在的结构体地址。
//接口的第一个入参表示的是链表中的头节点,第二个入参是指定的链表节点,
//第三个入参是要获取的结构体名称,第四个入参是链表在该结构体中的名称。
//如果链表节点下一个为链表头结点为空,返回NULL。
#define LOS_ListNextType(list, item, type, element) ({           \
    type *__t;                                                   \
    if ((item)->pstNext == list) {                               \
        __t = NULL;                                              \
    } else {                                                     \
        __t = LOS_DL_LIST_ENTRY((item)->pstNext, type, element); \
    }                                                            \
    __t;                                                         \
})

//获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,
//第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。
#define LOS_ListPeekHeadType(list, type, element) ({             \
    type *__t;                                                   \
    if ((list)->pstNext == list) {                               \
        __t = NULL;                                              \
    } else {                                                     \
        __t = LOS_DL_LIST_ENTRY((list)->pstNext, type, element); \
    }                                                            \
    __t;                                                         \
})
///遍历双向链表,并存储当前节点的后继节点用于安全校验
#define LOS_DL_LIST_FOR_EACH_SAFE(item, next, list)      \
    for (item = (list)->pstNext, next = (item)->pstNext; \
         (item) != (list);                               \
         item = next, next = (item)->pstNext)
 //遍历双向链表
#define LOS_DL_LIST_FOR_EACH(item, list) \
    for (item = (list)->pstNext;         \
         (item) != (list);               \
         item = (item)->pstNext)

//遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址
#define LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, next, list, type, member)               \
    for (item = LOS_DL_LIST_ENTRY((list)->pstNext, type, member),                     \
         next = LOS_DL_LIST_ENTRY((item)->member.pstNext, type, member);              \
         &(item)->member != (list);                                                   \
         item = next, next = LOS_DL_LIST_ENTRY((item)->member.pstNext, type, member)) 

void initBook(LOS_DL_LIST *head){
    Book *book1 = (Book*)malloc(sizeof(Book));  //堆上分配
    Book *book2 = (Book*)malloc(sizeof(Book));
    Book *book3 = (Book*)malloc(sizeof(Book));
    Book *book4 = (Book*)malloc(sizeof(Book));
    memset(book1,0,sizeof(Book));
    memset(book2,0,sizeof(Book));
    memset(book3,0,sizeof(Book));
    memset(book4,0,sizeof(Book));

    strcpy(book1->author,"罗贯中");
    strcpy(book1->name,"三国演义");
    book1->price = 45.99;

    strcpy(book2->author,"曹雪芹");
    strcpy(book2->name,"红楼梦");
    book2->price = 30.3;

    strcpy(book3->author,"吴承恩");
    strcpy(book3->name,"西游记");
    book3->price = 50.38;

    strcpy(book4->author,"施耐庵");
    strcpy(book4->name,"水浒传");
    book4->price = 66.3;


    LOS_ListAdd(head,&(book1->otherBook));
    LOS_ListAdd(head,&(book2->otherBook));
    LOS_ListAdd(head,&(book3->otherBook));
    LOS_ListAdd(head,&(book4->otherBook));

    LOS_DL_LIST *item = NULL;
    LOS_DL_LIST *next = NULL;
    LOS_DL_LIST_FOR_EACH_SAFE(item, next, head){
        Book *bookbook = LOS_DL_LIST_ENTRY(item,Book,otherBook);
        print_book(bookbook);
    }
}
int main(){
    
    LOS_DL_LIST *head= (LOS_DL_LIST*)malloc(sizeof(LOS_DL_LIST));
    LOS_ListInit(head);
    initBook(head);
    
    cout<<"======================\n";
    LOS_DL_LIST pBook;

    LOS_ListInit(&pBook);

    Book book = {"三国演艺", "罗贯中",100.5};
    Book book1 = {"红楼梦", "曹雪芹",200.5};
    Book book2 = {"西游记",  "吴承恩",150.1};
    Book book3 = {"水浒传", "施耐庵",180.4};

    Book * book_ = LOS_DL_LIST_ENTRY(&book.otherBook,Book,otherBook);
    cout<<(book_ == &book)<<endl;
    
    LOS_ListAdd(&pBook,&(book.otherBook));
    LOS_ListAdd(&pBook,&(book1.otherBook));
    LOS_ListAdd(&pBook,&(book2.otherBook));
    LOS_ListAdd(&pBook,&(book3.otherBook));

    cout<<"获取双向链表下一个数据节点:\n";
    Book *b = LOS_ListNextType(&pBook, &book3.otherBook, Book, otherBook);
    if(b != NULL)print_book(b);
    cout<<"获取双向链表下一个数据节点结束\n\n";

    cout<<"获取双向链表第一个数据节点:\n";
    Book *firstBook = LOS_ListPeekHeadType(&pBook,Book,otherBook);
    print_book(firstBook);
    cout<<"获取双向链表第一个数据节点结束\n\n";

    cout<<"while 遍历:\n";
    LOS_DL_LIST *book_item = pBook.pstNext;

    while(book_item != &pBook){
        Book *bookbook = LOS_DL_LIST_ENTRY(book_item,Book,otherBook);
        print_book(bookbook);
        book_item = book_item->pstNext;
    }
    cout<<"while 遍历结束:\n\n";
    

    cout<<"宏定义遍历\n";
    LOS_DL_LIST* item = NULL;
    LOS_DL_LIST*next = NULL;
    LOS_DL_LIST_FOR_EACH_SAFE(item, next, &pBook){
        Book *bookbook = LOS_DL_LIST_ENTRY(item,Book,otherBook);
        print_book(bookbook);
    }
    cout<<"宏定义遍历结束\n\n";
    cout<<"for each 遍历\n";
    LOS_DL_LIST_FOR_EACH(item,&pBook){
        Book *bookbook = LOS_DL_LIST_ENTRY(item,Book,otherBook);
        print_book(bookbook);
    }
    cout<<"for each 遍历结束\n\n\n";

    Book* book_item_item = NULL;
    Book* book_next = NULL;
    LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(book_item_item, book_next, &pBook, Book, otherBook){
        print_book(book_item_item);

    }


}

在这里插入图片描述

参考链接

http://weharmonyos.com/blog/01.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/14633.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法:在指定范围内生成随机不重复的位置

问题&#xff1a; 在游戏中&#xff0c;我们经常会遇到以下问题&#xff1a;在指定的范围内生成随机不重复的位置。 比如某次“神官赐福”活动中&#xff0c;需要在城门口生成n个不重复的宝箱。 针对这种问题&#xff0c;我们可以先将范围按照宝箱&#xff08;基本单元格&#…

【代码随想录】刷题Day5

1.链表重复节点删除 82. 删除排序链表中的重复元素 II 前后指针实现 1.做这道题最大的感受就是&#xff1a;不要觉得开辟空间浪费&#xff0c;多用临时变量去记录。越精确越容易成功 2.首先没有节点或者一个节点直接返回 3.因为头部会出现一样元素的情况&#xff0c;以至于我不…

Transformer 位置编码代码解析

Transformer 位置编码代码解析 Transformer 的 Multi-Head-Attention 无法判断各个编码的位置信息。因此 Attention is all you need 中加入三角函数位置编码&#xff08;sinusoidal position embedding&#xff09;&#xff0c;表达形式为&#xff1a; P E ( p o s , 2 i ) …

springboot +flowable,处理 flowable 的用户和用户组(一)

一.简介 对于flowable是什么以及关于此框架的具体信息可以参看此项目的官方文档&#xff1a;https://www.flowable.org/docs/userguide/index.html Flowable is a light-weight business process engine written in Java.这是官网文档对此框架的完美解释&#xff1a;Flowable…

养老保障金查询系统【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址&#xff1a;https://download.csdn.net/download/qq_50954361/87700421 更多系统资源库…

Redis入门学习笔记【二】Redis缓存

目录 一、Redis缓存 二、Redis使用缓存遇到的问题 2.1 数据一致性 2.2缓存雪崩 2.3 缓存穿透 2.4 缓存击穿 一、Redis缓存 数据缓存是Redis最重要的一个场景&#xff0c;为缓存而生&#xff0c;在springboot中&#xff0c;一般有两种使用方式&#xff1a; 直接通过RedisT…

【无人机】无人机平台的非移动 GPS 干扰器进行位置估计的多种传感器融合算法的性能分析(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

leetcode142_环形链表 II

文章目录 题目详情分析Java完整代码 题目详情 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给…

「数据架构」MDM实现失败的主要原因

我经常参与一个组织的MDM程序&#xff0c;当他们在一个失败的项目之后向InfoTrellis请求帮助进行清理&#xff0c;或者开始尝试X&#xff0c;以实现对某些人来说非常困难的目标时。主数据管理实现失败的原因有很多&#xff0c;但是没有一个是由于在这些场景中使用的责备游戏的原…

MySQL-中间件mycat(一)

目录 &#x1f341;mycat基础概念 &#x1f341;Mycat安装部署 &#x1f343;初始环境 &#x1f343;测试环境 &#x1f343;下载安装 &#x1f343;修改配置文件 &#x1f343;启动mycat &#x1f343;测试连接 &#x1f990;博客主页&#xff1a;大虾好吃吗的博客 &#x1f9…

找网站绝对路径

目录 Linux系统 目标出网。且命令有回显 目标出网&#xff0c;命令无回显 目标不出网&#xff0c;命令无回显 Windows系统 目标出网&#xff0c;命令有回显 目标出网&#xff0c;命令无回显 目标不出网&#xff0c;命令无回显 Linux系统 目标出网。且命令有回显 find …

gpt在线使用-免费的 GPT在哪下载

免费的 GPT&#xff08;Generative Pre-trained Transformer&#xff09; 。现在您可以免费体验我们的 GPT 技术&#xff0c;来让您的业务或项目更加智能。 GPT 是一种基于最前沿的自然语言处理技术&#xff0c;它展现出了令人惊叹的预测能力和交互性能。我们的 GPT 是在世界顶…

SQL Compliance Manager Crack

SQL Compliance Manager Crack 新的SQL CM云代理-扩展了当前SQL CM代理的功能&#xff0c;以支持EC2上Microsoft SQL服务器的远程审核。允许用户添加在共享网络位置上活动的SQL Server&#xff0c;以写入/读取数据并支持DBaaS SQL Server实例。云代理包含与当前SQL代理相同的行…

被chatGPT割了一块钱韭菜

大家好&#xff0c;才是真的好。 chatGPT热度一直上升&#xff0c;让我萌生了一个胆大而创新的想法&#xff0c; 把chatGPT嵌入到Notes客户机中来玩。 考虑到我已经下载了一个chatGPT的Notes应用&#xff08;请见《ChatGPT APIs for HCL DOMINO》&#xff09;&#xff0c;想着…

No.045<软考>《(高项)备考大全》【专项1】《案例分析 - 简介、方法、技巧、理论》

《案例分析》 1 专项介绍1.1 考试分析1.2 试卷参考1.3 题型分析 2 案例分析答题技巧2.1 考试6要2.2 三不要—可以2.3 其他技巧 3 案例中的万金油4 各领域中的重要工具与输出5 案例分析答题技巧6 案例分析理论题历年考点分析6.1 一般知识和科研立项6.2 整体、范围、需求6.3 进度…

我想知道,就目前形势而言,学java好还是C++好?

前言 就现实点看看&#xff0c;可以对比现在Java和C的市场占有率&#xff0c;可以看到&#xff0c;到目前为止&#xff0c;Java在国内编程语言的市场仍然是占据着大头&#xff0c;在招聘当中Java的人数占有率仍然是遥遥领先于C&#xff0c;Java目前开阔的市场以及其巨大的岗位…

风光场景削减及源荷不确定性的虚拟电厂随机优化调度研究(Matlab代码实现)

&#x1f4a5; &#x1f4a5; &#x1f49e; &#x1f49e; 欢迎来到本博客 ❤️ ❤️ &#x1f4a5; &#x1f4a5; &#x1f3c6; 博主优势&#xff1a; &#x1f31e; &#x1f31e; &#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 …

Python小姿势 - ###### 随机选取的知识点:Python日期时间处理

随机选取的知识点&#xff1a;Python日期时间处理 Python日期时间处理&#xff1a;一种更简单的方式 日期和时间处理是许多程序中必不可少的部分。Python提供了一个标准库来处理日期和时间&#xff0c;这个库叫做datetime&#xff0c;它提供了一些类来处理不同的日期和时间格式…

SpringCloud --- Nacos注册中心、配置管理

一、Nacos注册中心 1.1、认识和安装Nacos Nacos是阿里巴巴的产品&#xff0c;现在是SpringCloud中的一个组件。相比Eureka功能更加丰富&#xff0c;在国内受欢迎程度较高。 1.2、服务注册到nacos Nacos是SpringCloudAlibaba的组件&#xff0c;而SpringCloudAlibaba也遵循Spr…

基于U-Net系列的医学图像分割

U-Net 在FCN 的基础上增加了上采样操作的次数和跳跃连接&#xff0c;使用跳跃连接将解码器的输出特征与编码器的语义特征融合&#xff0c;提高了分割精度&#xff0c;改善了 FCN 上采样不足的问题。 U-Net中没有全连接层&#xff0c;通过互连卷积与反卷积过程中的特征&#xff…