Linux编程——经典链表list_head
1. 关于list_head
struct list_head
是Linux内核定义的双向链表,包含一个指向前驱节点和后继节点的指针的结构体。其定义如下:
struct list_head {struct list_head *next, *prev; //双向链表,指向节点的指针
};
1.1 链表的定义和初始化
有两种方式来定义和初始化链表头:
- 方法一:利用宏
LIST_HEAD
定义并初始化 - 方法二:先定义,再利用宏
INIT_LIST_HEAD
初始化
//方法1:利用LIST_HEAD定义并初始化链表
static LIST_HEAD(registered_llhw); //方法2:先定义再初始化链表
struct list_head registered_llhw; //定义一个链表(注册链路层hardware)
INIT_LIST_HEAD(®istered_llhw); //初始化链表//相关宏定义如下:
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)#define LIST_HEAD_INIT(name) { &(name), &(name)}//即初始化后链表的nexth和prev都指向自己。
#define INIT_LIST_HEAD(ptr) do { \(ptr)->next = (ptr); \(ptr)->prev = (ptr); \
}while(0)
1.2 链表节点增/删
使用list_add/list_add_tail来添加链表节点。
list_add(&entry, &ListHead);//在head之后添加
static inline void list_add(struct list_head *new, struct list_head *head)
{__list_add(new, head, head->next);
}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;
}//添加到head之前,即链表的尾部增加
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{__list_add(new, head->prev, head);
}#ifdef CONFIG_ILLEGAL_POINTER_VALUE
# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
#else
# define POISON_POINTER_DELTA 0
#endif// 定义两个特殊的宏,将已经释放的节点指向这个位置,避免重复删除一个已经被释放的节点,避免出现潜在的漏洞。
// 实际上还起到用于标记已经删除节点的意义。
#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)// 从双向链表中删除一个节点
static inline void list_del(struct list_head *entry)
{__list_del_entry(entry);entry->next = LIST_POISON1;entry->prev = LIST_POISON2;//为什么不直接指向空指针NULL?在正常环境下,这个非空指针将会引起页错误。//可被用来验证没有初始化的链表节点。可以区分是被list删除的还是本身没有初始化的,便于调试。
}static inline void __list_del(struct list_head *prev, struct list_head *next)
{next->prev = prev;WRITE_ONCE(prev->next, next);
}static inline __list_del_entry(struct list_head *entry)
{if(!__list_del_entry_valid(entry))return;__list_del(entry->prev, entry->next);
}
1.3 遍历链表中节点
list_for_each_entry
宏实际上是一个for循环,利用传入的pos作为循环变量,从表头head开始,逐项向后(next)移动pos,直到又回到head。
/*** list_for_each_entry - iterate over list of given type* @pos: the type * to use as a loop cursor* @head: the head for your list.* @member: the name of the list_struct within the struct*/
#define list_for_each_entry(pos, head, member) \for(pos = list_entry((head)->next, typeof(*pos), member); \prefetch(pos->member.netx), &pos->member != (head); \pos = list_entry(pos->member.next, typeof(*pos), member))// prefetch是告诉CPU哪些元素有可能马上要用到,预取一下,可以提高速度,用于预期以提高遍历速度// 从指针ptr中获取所在结构体类型type,并返回结构体指针。
// member是结构体中双向链表节点的成员名。注意,不能用于空链表和未初始化的链表。
/*** list_entry - get the struct for this entry* @ptr: the &struct list_head pointer* @type: the type of the struct this is embeded in* @member: the name of the list_struct within the struct */
#define list_entry(ptr, type, member) container_of(ptr, type, member)//container_of用于根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针/*** container_of - cast a member of a structrue out to the containing structure* @ptr: the pointer to the member* @type: the type of the container struct this is embeded in* @member: the name of the member within the struct*/
#define container_of(ptr, type, member) ({ \const typeof(((type *)0)->member )*__mptr = (ptr);(type *)((char *)__mptr - offsetof(type, member)); //得到结构体的地址,得到结构体指针})//强制将整型常量转换为TYPE型指针,指针指向的地址为0,也就是从0开始的一块存储空间映射为TYPE对象
//然后对MEMBER进行取地址,由于起始地址为0,也就获得MEMBER成员在TYPE中的偏移量,强制无符号整型
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
提示:对于container_of
,offsetof
宏,是Linux中常用的两个宏,用来处理结构体与结构体成员之间的指针转化。可以多加熟练与使用,在很多场景都可以得到应用。需要包含头文件<stddef.h>
。
相关文章:
Linux编程——经典链表list_head
1. 关于list_head struct list_head是Linux内核定义的双向链表,包含一个指向前驱节点和后继节点的指针的结构体。其定义如下: struct list_head {struct list_head *next, *prev; //双向链表,指向节点的指针 };1.1 链表的定义和初始化 有两…...

基于51单片机NEC协议红外遥控发送接收仿真设计( proteus仿真+程序+原理图+报告+讲解视频)
基于51单片机NEC协议红外遥控发送接收仿真设计 讲解视频1.主要功能:2.仿真3. 程序代码4. 原理图5. 设计报告6. 设计资料内容清单&&下载链接 基于51单片机NEC协议红外遥控发送接收仿真设计 51单片机红外发送接收仿真设计( proteus仿真程序原理图报告讲解视频…...

Jmeter分布式压力测试
目录 1、场景 2、原理 3、注意事项 4、slave配置 5、master配置 6、脚本执行 1、场景 在做性能测试时,单台机器进行压测可能达不到预期结果。主要原因是单台机器压到一定程度会出现瓶颈。也有可能单机网卡跟不上造成结果偏差较大。 例如4C8G的window server机…...
Rust :mod.rs和lib.rs中use的作用
一、mod.rs和lib.rs mod.rs往往是把同一目录下的n个rs文件综合在一起的有效方式; lib.rs是一个库或子库层次综合在一起的有效方式; 下面举个实例来说明。生成一个rusttoc本地库(由cargo new rusttoc --lib所生成),目录…...

ISP图像信号处理——平场校正介绍以及C++实现
参考文章1:http://t.csdn.cn/h8TBy 参考文章2:http://t.csdn.cn/6nmsT 参考网址3:opencv平场定标 - CSDN文库 平场校正一般先用FPN(Fixed Pattern Noise)固定图像噪声校正,即暗场校正;再用PRNU(Photo Response Non Uniformity)…...

【深入了解Java String类】
目录 String类 常用方法 字符串的不可变性 String的内存分析 StringBuilder类 解释可变和不可变字符串 常用方法 面试题:String,StringBuilder,StringBuffer之间的区别和联系 String类的OJ练习 String类 【1】直接使用,…...

基于SpringBoot的知识管理系统
目录 前言 一、技术栈 二、系统功能介绍 用户管理 文章分类 资料分类 文章信息 论坛交流 资料下载 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息互联网信息的飞速发展,无纸化作业变成了一种趋势,针对这个问题开发一个…...
Pytorch基础:Tensor的reshape方法
在Pytorch中,reshape是Tensor的一个重要方法,它与Numpy中的reshape类似,用于返回一个改变了形状但数据和数据顺序和原来一致的新Tensor对象。注意:此时返回的数据对象并不一定是新的,这取决于应用此方法的Tensor是否是…...

【数据库——MySQL】(13)过程式对象程序设计——存储函数、错误处理以及事务管理
目录 1. 存储函数2. 存储函数的应用3. 错误处理4. 抛出异常5. 事务处理6. 事务隔离级7. 应用实例参考书籍 1. 存储函数 要 创建 存储函数,需要用到 CREATE 语句: CREATE FUNCTION 存储函数名([参数名 类型, ...])RETURNS 类型[存储函数体]注意࿱…...

Spring Boot的魔法:构建高性能Java应用
文章目录 Spring Boot:简化Java开发Spring Boot的性能优势1. 内嵌服务器2. 自动配置3. 起步依赖4. 缓存和优化5. 异步处理 实际示例:构建高性能的RESTful API总结 🎉欢迎来到架构设计专栏~Spring Boot的魔法:构建高性能Java应用 ☆…...
如何做好测试?(七)兼容性测试 (Compatibility Testing, CT)
1. 兼容性测试介绍 兼容性测试 (Compatibility Testing, CT)是一种软件测试方法,旨在验证应用程序在不同操作系统、浏览器、设备和网络环境下的正确运行和一致性。对于网上购物系统来说,兼容性测试非常重要,因为用户可能使用各种不同的设备和…...

经典循环神经网络(一)RNN及其在歌词数据集上的应用
经典循环神经网络(一)RNN及其在歌词数据集上的应用 1 RNN概述 在深度学习兴起之前,NLP领域一直是统计模型的天下,例如词对齐算法GIZA,统计机器翻译开源框架MOSES等等。在语言模型方向,n-gram是当时最为流行的语言模型方法。n-gr…...
docker+mysql+flask+redis+vue3+uwsgi+docker部署
首先拉取mysql的镜像,这里用的mysql5.7.6 docker pull mysql:5.7.6 镜像拉取完成后启动: docker run --name my-mysql -d -p 3306:3306 -v /usr/local/my-mysql/conf:/etc/mysql/conf.d -v /usr/local/my-mysql/data:/var/lib/mysql -e MYSQL_ROOT_PA…...
Spring boot接收zip包并获取其中excel文件的方法
1、问题 工作中遇到一个需求,接收一个zip包,读取其中的excel文件并处理,减少用户多次选择目录和文件的痛点,该zip包包含多级目录 2、依赖 需要用到apache的Workbook类来操作Excel,引入以下依赖 <dependency>&l…...

Ubuntu镜像源cn.arichinve.ubuntu.com不可用原因分析和解决
文章目录 Ubuntu查看系统版本Ubuntu更新系统不能更新Ubuntu查看APT更新源配置cn.archive.ubuntu.com已经自动跳转到清华镜像站Ubuntu变更镜像源地址备份原文件批量在VIM中变更 Ubuntu国内镜像站推荐推荐阅读 今天想要在Ubuntu环境下搭建一个测试环境,进入Ubuntu系统…...
Java基础面试,String,StringBuffer,StringBuilder区别以及使用场景
简单的几句 String是final修饰的,不可变,每次操作都会产生新的对象。StringBuffer和StringBuilder都是在原对象上进行操作StringBuffer是线程安全的,StringBuilder是线程不安全的。StringBuffer方法是被synchronized修饰的 所以在性能方面大…...

基于SpringBoot的高校学科竞赛平台
目录 前言 一、技术栈 二、系统功能介绍 竞赛题库管理 竞赛信息管理 晋级名单管理 往年成绩管理 参赛申请管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步…...

excel如何让线条消失,直接设置网格即可,碰到不方便的地方优先百度,再采取蛮干
怎么将excel表格中的隐形线条去掉...

抖音短视频seo矩阵系统源代码开发系统架构及功能解析
短视频seo源码,短视频seo矩阵系统底层框架上支持了从ai视频混剪,视频批量原创产出,云存储批量视频制作,账号矩阵,视频一键分发,站内实现关键词、短视频批量搜索排名,数据统计分类多功能细节深度…...

在pycharm中弹出图后,需要关闭才会显示Process finished with exit code 0
在pycharm中弹出图后,需要关闭才会显示Process finished with exit code 0 在PyCharm中,当你运行一个Python程序并弹出一个图形窗口时,程序会等到图形窗口关闭后才会显示 “Process finished with exit code 0” 的消息。 这是 由于代码执行…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...

消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...