内核链表在用户程序中的移植和使用
基础知识
struct list_head {struct list_head *next, *prev;
};
初始化:
#define LIST_HEAD_INIT(name) { (name)->next = (name); (name)->prev = (name);}
相比于下面这样初始化,前面初始化的好处是,处理链表的时候,不用判空了。太厉害了。
#define LIST_HEAD_INIT(name) { (name)->next = (NULL); (name)->prev = (NULL);}
遍历链表:
/*** list_for_each - iterate over a list* @pos: the &struct list_head to use as a loop cursor.* @head: the head for your list.*/
#define list_for_each(pos, head) \for (pos = (head)->next; pos != (head); pos = pos->next)
添加节点:(表头开始添加)
/** Insert a new entry between two known consecutive entries.** This is only for internal list manipulation where we know* the prev/next entries already!*/
static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)
{next->prev = new;new->next = next;new->prev = prev;prev->next = new;
}/*** list_add - add a new entry* @new: new entry to be added* @head: list head to add it after** Insert a new entry after the specified head.* This is good for implementing stacks.*/
static inline void list_add(struct list_head *new, struct list_head *head)
{__list_add(new, head, head->next);
}
添加节点:(表尾开始添加)
/** Insert a new entry between two known consecutive entries.** This is only for internal list manipulation where we know* the prev/next entries already!*/
static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)
{next->prev = new;new->next = next;new->prev = prev;prev->next = new;
}
/*** list_add_tail - add a new entry* @new: new entry to be added* @head: list head to add it before** Insert a new entry before the specified head.* This is useful for implementing queues.*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{__list_add(new, head->prev, head);
}
删除节点
/** Delete a list entry by making the prev/next entries* point to each other.** This is only for internal list manipulation where we know* the prev/next entries already!*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{next->prev = prev;prev->next = next;
}static inline void list_del(struct list_head *entry)
{__list_del(entry->prev, entry->next);LIST_HEAD_INIT(entry);
}
判空:
/*** list_empty - tests whether a list is empty* @head: the list to test.*/
static int list_empty(const struct list_head *head)
{return (head->next) == head;
}
基本功能就这些了
测试代码
#include <stdio.h>
#include <stdlib.h>#define _DEBUG_INFO
#ifdef _DEBUG_INFO#define DEBUG_INFO(format,...) \printf("%s:%d -- "format"\n",\__func__,__LINE__,##__VA_ARGS__)
#else#define DEBUG_INFO(format,...)
#endifstruct list_head {struct list_head *next, *prev;
};struct rcu_private_data{struct list_head list;
};struct my_list_node{struct list_head node;int number;
};/*** list_for_each - iterate over a list* @pos: the &struct list_head to use as a loop cursor.* @head: the head for your list.*/
#define list_for_each(pos, head) \for (pos = (head)->next; pos != (head); pos = pos->next)#define LIST_HEAD_INIT(name) { (name)->next = (name); (name)->prev = (name);}#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \void *__mptr = (void *)(ptr); \((type *)(__mptr - offsetof(type, member))); })/*** list_empty - tests whether a list is empty* @head: the list to test.*/
static int list_empty(const struct list_head *head)
{return (head->next) == head;
}/** Insert a new entry between two known consecutive entries.** This is only for internal list manipulation where we know* the prev/next entries already!*/
static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)
{next->prev = new;new->next = next;new->prev = prev;prev->next = new;
}/*** list_add - add a new entry* @new: new entry to be added* @head: list head to add it after** Insert a new entry after the specified head.* This is good for implementing stacks.*/
static inline void list_add(struct list_head *new, struct list_head *head)
{__list_add(new, head, head->next);
}/*** list_add_tail - add a new entry* @new: new entry to be added* @head: list head to add it before** Insert a new entry before the specified head.* This is useful for implementing queues.*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{__list_add(new, head->prev, head);
}/** Delete a list entry by making the prev/next entries* point to each other.** This is only for internal list manipulation where we know* the prev/next entries already!*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{next->prev = prev;prev->next = next;
}static inline void list_del(struct list_head *entry)
{__list_del(entry->prev, entry->next);LIST_HEAD_INIT(entry);
}static int list_size(struct rcu_private_data *p){struct list_head *pos;struct list_head *head = &p->list;int count = 0;if(list_empty(&p->list)){DEBUG_INFO("list is empty");return 0;}list_for_each(pos,head){count++;}return count;
}static int show_list_nodes(struct rcu_private_data *p){struct list_head *pos;struct list_head *head = &p->list;int count = 0;struct my_list_node *pnode;if(list_empty(&p->list)){DEBUG_INFO("list is empty");return 0;}list_for_each(pos,head){pnode = (struct my_list_node*)container_of(pos,struct my_list_node,node);DEBUG_INFO("pnode->number = %d",pnode->number);count++;}return count;
}int main(int argc, char **argv){int i = 0;static struct my_list_node * new[6];struct rcu_private_data *p = (struct rcu_private_data*)malloc(sizeof(struct rcu_private_data));LIST_HEAD_INIT(&p->list);DEBUG_INFO("list_empty(&p->list) = %d",list_empty(&p->list));for(i = 0;i < 3;i++){new[i] = (struct my_list_node*)malloc(sizeof(struct my_list_node));LIST_HEAD_INIT(&new[i]->node);new[i]->number = i;list_add(&new[i]->node,&p->list);}for(i = 3;i < 6;i++){new[i] = (struct my_list_node*)malloc(sizeof(struct my_list_node));LIST_HEAD_INIT(&new[i]->node);new[i]->number = i;list_add_tail(&new[i]->node,&p->list);}//输出链表节点数DEBUG_INFO("list_size(&p->list) = %d",list_size(p));//遍历链表show_list_nodes(p);//删除指定节点list_del(&new[3]->node);DEBUG_INFO("list_size(&p->list) = %d",list_size(p));//遍历链表show_list_nodes(p);for(i = 0;i < 6;i++){list_del(&new[i]->node);}DEBUG_INFO("list_size(&p->list) = %d",list_size(p));//遍历链表show_list_nodes(p);for(i = 0;i < 6;i++){free(new[i]);}free(p);return 0;
}
编译
gcc -o app app.c
执行结果:

小结
相关文章:
内核链表在用户程序中的移植和使用
基础知识 struct list_head {struct list_head *next, *prev; }; 初始化: #define LIST_HEAD_INIT(name) { (name)->next (name); (name)->prev (name);} 相比于下面这样初始化,前面初始化的好处是,处理链表的时候,不…...
使用C#基于ComPDFKit SDK快速构建PDF阅读器
在当今世界,Windows 应用程序对我们的工作至关重要。随着处理 PDF 文档的需求不断增加,将 ComPDFKit PDF 查看和编辑功能集成到您的 Windows 应用程序或系统中,可以极大地为您的用户带来美妙的体验。 在本博客中,我们将首先探索集…...
el-tabel导出excel表格
1、安装插件 npm install file-saver --save npm install xlsx --save 2、引入插件 import FileSaver from "file-saver"; import * as XLSX from xlsx; 3、在tabel中添加ref属性和导出方法 4、添加方法 exportExcel (excelName) {try {const $e this.$refs[repo…...
双击start.bat文件闪退,运行报错“unable to access jarfile”
问题:电脑运行“start.bat”文件,无反应,闪退,管理员身份运行报错“unable to access jarfile” 解决思路: 1、由于该项目运行需要jdk环境,检查jdk版本需要是1.8.0_251版本 通过在 cmd 命令行输入java -v…...
大数据Flink(五十一):Flink的引入和Flink的简介
文章目录 Flink的引入和Flink的简介 一、Flink的引入 1、第1代——Hadoop MapReduce...
c语言的数据类型 -- 与GPT对话
1 c语言的数据类型 在C语言中,数据类型用于定义变量的类型和存储数据的方式。C语言支持多种数据类型,包括基本数据类型和派生数据类型。以下是C语言中常见的数据类型: 基本数据类型(Primary Data Types): int: 整数类型,通常表示带符号的整数。char: 字符类型,用于存储…...
Truffle 进行智能合约测试
其他依赖 node.js、 由于是利用npm进行,所以先设置国内镜像源。去网上搜 1.安装truffle npm install truffle -gtruffle --version 安装完其他项目依赖,能够产生一下效果 2.项目创建 创建test文件夹 mkdir test进入test cd test初始化项目 truffle …...
vb+access库存管理系统设计与实现
第一章库存信息管理系统的基本问题 1.1 库存信息管理系统的简介 本系统是为了提高腾达公司自动化办公的水平、经过详细的调查分析初步制定了腾达公司库存信息管理系统。基于WINDOWS 98 平台,使用Microsoft Access97, 在Visual Basic 6.0编程环境下开发的库存信息管理系统。该…...
机器学习03-数据理解(小白快速理解分析Pima Indians数据集)
机器学习数据理解是指对数据集进行详细的分析和探索,以了解数据的结构、特征、分布和质量。数据理解是进行机器学习项目的重要第一步,它有助于我们对数据的基本属性有全面的了解,并为后续的数据预处理、特征工程和模型选择提供指导。 数据理解…...
Hadoop生态体系-HDFS
目录标题 1、Apache Hadoop2、HDFS2.1 设计目标:2.2 特性:2.3 架构2.4 注意点2.5 HDFS基本操作2.5.1 shell命令选项2.5.2 shell常用命令介绍 3、HDFS基本原理3.1 NameNode 概述3.2 Datanode概述 1、Apache Hadoop Hadoop:允许使用简单的编程…...
《实战AI模型》——赶上GPT3.5的大模型LLaMA 2可免费商用,内含中文模型推理和微调解决方案
目录 准备环境及命令后参数导入: 导入模型: 准备LoRA: 导入datasets: 配置Config:...
工程安全监测无线振弦采集仪在建筑物的应用分析
工程安全监测无线振弦采集仪在建筑物的应用分析 工程安全监测无线振弦采集仪是一种在建筑物中应用的重要设备。它通过无线采集建筑物内部的振动信息,对建筑物的安全性进行监测和评估,为建筑物的施工和使用提供了可靠的技术支持。本文将详细介绍工程安全…...
OpenCV实现照片换底色处理
目录 1.导言 2.引言 3.代码分析 4.优化改进 5.总结 1.导言 在图像处理领域,OpenCV是一款强大而广泛应用的开源库,能够提供丰富的图像处理和计算机视觉功能。本篇博客将介绍如何利用Qt 编辑器调用OpenCV库对照片进行换底色处理,实现更加…...
安科瑞智能型BA系列电流传感器
安科瑞虞佳豪 壹捌柒陆壹伍玖玖零玖叁 选型...
Windows SMB 共享文件夹 排错指南
1 排错可能 是否系统名称为全英文格式 如果不是则 重命名 根据如下排错可能依次设置 1,在运行里面输入"secpol.msc"来启动本地安全设置,\ 然后选择本地策略–>安全选项 -->网络安全LAN 管理器身份验证级别,\ “安全设置”…...
nestjs+typeorm+mysql基本使用学习
初始化项目 安装依赖 npm i -g nest/cli 新建项目 nest new project-name 命令行创建 创建Controller:nest g co test 创建Module:nest g mo test 创建Service:nest g service test 请求创建 123123 接口文档swagger 安装依赖 npm…...
echarts柱状图每根柱子添加警戒值/阈值,分段警戒线
需求:柱状图每根柱子都添加单独的警戒值(黄色线部分),效果图如下: 实现方式我这有两种方案,如下介绍。 方案1:使用echarts的标线markLine实现(ps:此种方案有弊端&#x…...
边缘提取总结
边缘提取:什么是边缘? 图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般可以 看作是一个阶跃,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相 差较大的灰度值。 边缘有正负之分,就像…...
intellij 编辑器内性能提示
介绍 IntelliJ IDEA已经出了最新版的2023.2,最耀眼的功能无法两个 AI Assistant编辑器内性能提示 AI Assistant 已经尝试过了是限定功能,因为是基于open ai,所以限定的意思是国内无法使用,今天我们主要介绍是编辑器内性能提示 IntelliJ Pr…...
手机python怎么用海龟画图,python怎么在手机上编程
大家好,给大家分享一下手机python怎么用海龟画图,很多人还不知道这一点。下面详细解释一下。现在让我们来看看! 1、如何python手机版创造Al? 如果您想在手机上使用Python来创建AI(人工智能)程序࿰…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
