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

news2024/11/24 5:49:18

不一样的双向链表

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

链表初识别

最近看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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FPGA入门系列12--RAM的使用

文章简介 本系列文章主要针对FPGA初学者编写&#xff0c;包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解&#xff0c;旨在更快速的提升初学者在FPGA开发方面的能力&#xff0c;每一个章节中都有针对性的代码…

Spring IOC DI - 整合MyBatis

Spring IOC目录 主要内容Spring 框架介绍Spring 框架的优势(对比以前项目的缺点)Spring 框架引入历史发展框架学习三要素Spring 模块介绍 Spring IoC/DI - 引入IoC/DI 概念辨析使用IoC/DI的好处IoC/DI具体应用场景 Spring IoC/DI - 代码实现环境准备Spring 框架环境搭建创建Mav…

图的遍历和应用

文章目录 图的遍历深度优先遍历对于无向图的邻接矩阵的深度优先遍历无向非连通图的深度优先遍历 对于无向图的邻接表的深度优先遍历非递归实现深度优先遍历无向图的邻接矩阵代码实现无向图的邻接表代码实现递归和非递归的同异 广度优先遍历邻接表BFS邻接矩阵BFS 图的应用生成树…

Android 拍照以及相册中选择(适配高版本)————上传头像并裁剪(一)

前言 在项目研发中&#xff0c;相信大家都遇到过给用户增加头像照片的需求。 随着手机版本的不断更新&#xff0c;android 8、android 9、android 10、android 12、android 13、鸿蒙系统等等&#xff1b;遇到这个功能需求&#xff0c;大家肯定会想&#xff0c;“这还不好写&…

“双碳”目标下二氧化碳地质封存技术应用前景及模型构建实践方法

二氧化碳地质封存技术起步较晚&#xff0c;目前仍没有一套相对完整的行业规范&#xff1b;且就该技术而言&#xff0c;涉及环节众多&#xff0c;理论相对复杂&#xff0c;对于行业的新入局者不太友好。因此&#xff0c;结合时代背景&#xff0c;我们首次尝试对二氧化碳地质封存…

【裸金属服务器】安装VMware ESXi

官方安装操作ESXi地址 一、虚拟化服务器分类&#xff1a; 寄居架构&#xff08;Hosted Architecture&#xff09;和裸金属架构&#xff08;Bare Metal Architecture&#xff09;。 1、寄居架构&#xff08;Hosted Architecture&#xff09;&#xff1a;在操作系统之上安装和运…

8.系统日志

1.api访问日志 对应数据库 拦截器 拦截逻辑 ApiAccessLogFilter类的createApiAccessLog方法 buildApiAccessLogDTO方法就是完善实体类&#xff0c;把接口执行时长之类的填充完整。 然后就是保存日志到infra_api_access_log数据库。 过滤器注册生效 2.api错误日志 对应数…

Windows 程序开机自启动速度优化,为什么腾讯会议自启动速度那么高?

目录 一、问题的说明和定义 二、问题的分析 1.问题初步分析 2.详细的分析&#xff1a; 2.1Windows常见的自启动方式 2.2Windows常见的自启动方式的细节分析 三、问题的解决方案 1、为什么腾讯会议Rooms那么快 2.我们是否可以跟腾讯会议一样快 一、问题的说明和定义 这…

Vue之插件的定义和使用

概述 学习本文之前&#xff0c;我们需要弄清楚何为插件&#xff1f;插件其实就是一段扩展程序&#xff0c;主要目的是用于扩展功能。就比如Idea家族和VSCode家族的插件&#xff0c;它们也是一段扩展程序&#xff0c;将其安装到IDE中就可以使用插件里面实现的功能了&#xff0c…

SCADA平台的HMI功能

01 前言 虹科Panorama SCADA平台支持桌面HMI、Web HMI和移动HMI的功能。桌面HMI主要是在桌面工作站实现数据可视化&#xff0c;能够获取到最全面的数据信息以及实现功能&#xff1b;Web HMI可以通过在软件中添加Web HMI服务器&#xff0c;运行程序后&#xff0c;可以在Web 客户…

HTML5基础知识总结总结(详细,附带源代码)

HTML5基础知识 一&#xff1a;前言二&#xff1a; HTML基本结构。三&#xff1a;基本标签3.1 h标签3.2 p标签3.3 hr标签3.4 br标签3.5 strong标签与em标签3.6 特殊符号3.7 运行效果 三&#xff1a;图像标签四&#xff1a;链接标签五&#xff1a;列表六&#xff1a;表格七&#…

Allegro PCB后处理和生产文件导出

Allegro PCB后处理&#xff0c;主要是完成线路设计以后&#xff0c;输出生产文件之前的处理。部分是看教程做的记录&#xff0c;方便以后自己参考。 教程&#xff1a; [小哥Cadence Allegro 132讲字幕版PCB视频教程]_哔哩哔哩_bilibili 感觉关键是多看右边Options菜单&#xf…

【15】SCI易中期刊推荐——电子电气 | 仪器仪表(中科院4区)

💖💖>>>加勒比海带,QQ2479200884<<<💖💖 🍀🍀>>>【YOLO魔法搭配&论文投稿咨询】<<<🍀🍀 ✨✨>>>学习交流 | 温澜潮生 | 合作共赢 | 共同进步<<<✨✨ 📚📚>>>人工智能 | 计算机视觉…

[NISACTF 2022]level-up

[NISACTF 2022]level-up f12 发现提示disallow 也就是不允许的想到robots.txt LEVEL_2 <?php //here is level 2 error_reporting(0); #屏蔽报错信息 include "str.php"; #包含str.php这个页面 if (isset($_POST[array1]) && isset($_POST[arr…

巧用千寻位置GNSS软件|如何快速完成道路桥涵放样

道路桥涵放样主要解决道路施工中正交、斜交涵洞的测量&#xff0c;正交涵洞放样是中心线的定线放样&#xff1b;斜交涵洞放养是涵洞中心线与线路成一固定夹角的情况下的放样。 那么如何运用千寻位置GNSS软件实现道路桥涵放样呢&#xff1f;下面为各位一一介绍。 点击【测量】-&…

【移动端网页布局】移动端网页布局基础概念 ⑨ ( webkit 内核 | 移动端网页 CSS 初始化 - normalize.css )

文章目录 一、webkit 内核二、移动端网页 CSS 初始化 - normalize.css 一、webkit 内核 移动端浏览器 都是 基于 webkit 内核的 , QQ 浏览器 / 百度 / Safari / UC 都是基于 webkit 内核的 ; 移动端网页布局需要 兼容 普通浏览器 与 webkit 浏览器 ; webkit 内核浏览器 对 HT…

Ubuntu18 更换 apt 源为阿里云

Step1. 备份 list 文件 进入对应文件夹&#xff0c;用管理员权限&#xff0c;执行复制操作&#xff1a; cd /etc/apt/ sudo cp sources.list sources.list.bak Step2. 修改 list 文件 通过管理员权限&#xff0c;使用 vim 进行修改&#xff1a; sudo vim sources.list 将…

【Pytorch】六行代码实现:特征图提取与特征图可视化

前言 之前记录过特征图的可视化&#xff1a;Pytorch实现特征图可视化&#xff0c;当时是利用IntermediateLayerGetter 实现的&#xff0c;但是有很大缺陷&#xff0c;只能获取到一级的子模块的特征图输出&#xff0c;无法获取内部二级子模块的输出。今天补充另一种Pytorch官方…

ChatGPT如何写作-ChatGPT写作程序

ChatGPT如何写作 ChatGPT是一款自然语言处理模型&#xff0c;它无法像人类一样进行“写作”。但是&#xff0c;您可以利用ChatGPT的生成文本功能来帮助您生成文字。以下是一些使用ChatGPT写作的建议&#xff1a; 确定主题和目标受众。在开始写作之前&#xff0c;请确保您清楚知…

凝心聚力,携“源”出海:开源社顾问委员会2023年第一季度会议圆满举办!

2023 年 3 月 25 日&#xff0c;开源社顾问委员会&#xff08;以下简称"顾问委员会"&#xff09;第一季度会议在北京圆满召开。这是顾问委员会自 2018 年成立以来的第 17 次全体委员会议。 为增进顾问委员会成员交流&#xff0c;加强开源社社区建设&#xff0c;实现开…