Linux内核常用接口和宏(一)LIST_HEAD
一、LIST_HEAD是什么LIST_HEAD是 Linux 内核中定义并初始化链表头的宏。它用于创建一个双向循环链表的头部节点。c复制下载#include linux/list.h LIST_HEAD(my_list);这个宏展开后等价于c复制下载struct list_head my_list { my_list, my_list };即创建一个名为my_list的链表头它的next和prev指针都指向自己空链表状态。二、内核链表的定义内核链表不是将链表指针嵌入数据中而是将链表节点嵌入数据结构中——这是一种侵入式链表设计。c复制下载// 链表节点结构内核定义 struct list_head { struct list_head *next; struct list_head *prev; }; // 使用时将 list_head 嵌入到你的数据结构中 struct my_data { int id; char name[20]; struct list_head list; // 链表节点 };三、LIST_HEAD的使用方式方式1LIST_HEAD定义链表头c复制下载#include linux/list.h #include linux/slab.h #include linux/module.h // 定义链表头静态初始化 LIST_HEAD(my_list); struct my_data { int id; char name[20]; struct list_head list; }; // 添加节点 void add_node(int id, const char *name) { struct my_data *node; node kmalloc(sizeof(*node), GFP_KERNEL); if (!node) return; node-id id; strncpy(node-name, name, sizeof(node-name) - 1); node-name[sizeof(node-name) - 1] \0; // 插入到链表头部 list_add(node-list, my_list); } // 遍历链表 void print_list(void) { struct my_data *entry; struct list_head *pos; list_for_each(pos, my_list) { entry list_entry(pos, struct my_data, list); printk(KERN_INFO ID: %d, Name: %s\n, entry-id, entry-name); } }方式2LIST_HEAD_INIT动态初始化如果链表头是动态分配的用LIST_HEAD_INIT初始化c复制下载struct list_head *my_list; my_list kmalloc(sizeof(*my_list), GFP_KERNEL); LIST_HEAD_INIT(my_list); // 或者 INIT_LIST_HEAD(my_list)四、内核链表的核心操作函数/宏作用LIST_HEAD(name)定义并初始化链表头INIT_LIST_HEAD(head)初始化已存在的链表头list_add(new, head)在 head 后面插入新节点头插list_add_tail(new, head)在 head 前面插入新节点尾插list_del(entry)从链表中删除节点list_empty(head)判断链表是否为空list_for_each(pos, head)遍历链表pos 是 list_head*list_for_each_safe(pos, n, head)安全遍历支持删除list_entry(ptr, type, member)从 list_head 获取包含它的结构体五、list_entry详解list_entry是内核链表最精妙的部分它通过成员指针反推结构体首地址。c复制下载#define list_entry(ptr, type, member) \ container_of(ptr, type, member) #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)-member) *__mptr (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); \ })原理用offsetof计算member在结构体中的偏移量然后用ptr减去这个偏移量得到结构体的首地址。c复制下载struct my_data { int id; char name[20]; struct list_head list; // 假设偏移量是 24 字节 }; // 已知 node-list反推 node 的地址 struct my_data *node list_entry(node-list, struct my_data, list); // 等价于: (struct my_data*)((char*)node-list - 24)六、完整示例内核模块c复制下载#include linux/module.h #include linux/kernel.h #include linux/list.h #include linux/slab.h MODULE_LICENSE(GPL); // 定义链表头 LIST_HEAD(my_list); struct student { int id; char name[20]; struct list_head list; }; // 添加学生 static void add_student(int id, const char *name) { struct student *s kmalloc(sizeof(*s), GFP_KERNEL); if (!s) return; s-id id; snprintf(s-name, sizeof(s-name), %s, name); list_add_tail(s-list, my_list); // 尾插 } // 遍历打印 static void print_students(void) { struct student *s; struct list_head *pos; printk(KERN_INFO Student List \n); list_for_each(pos, my_list) { s list_entry(pos, struct student, list); printk(KERN_INFO ID: %d, Name: %s\n, s-id, s-name); } } // 删除指定 ID 的学生 static void delete_student(int id) { struct student *s; struct list_head *pos, *n; list_for_each_safe(pos, n, my_list) { s list_entry(pos, struct student, list); if (s-id id) { list_del(pos); kfree(s); printk(KERN_INFO Deleted student ID: %d\n, id); return; } } printk(KERN_INFO Student ID %d not found\n, id); } // 清空链表 static void clear_list(void) { struct student *s; struct list_head *pos, *n; list_for_each_safe(pos, n, my_list) { s list_entry(pos, struct student, list); list_del(pos); kfree(s); } } // 模块初始化 static int __init my_init(void) { printk(KERN_INFO Module loaded\n); add_student(1, Alice); add_student(2, Bob); add_student(3, Charlie); print_students(); delete_student(2); print_students(); return 0; } // 模块卸载 static void __exit my_exit(void) { clear_list(); printk(KERN_INFO Module unloaded\n); } module_init(my_init); module_exit(my_exit);七、LIST_HEAD与其他初始化方式对比方式代码适用场景LIST_HEAD(name)LIST_HEAD(my_list);静态定义链表头全局/局部变量INIT_LIST_HEAD(head)INIT_LIST_HEAD(my_list);动态初始化已存在的链表头LIST_HEAD_INIT(name)struct list_head my_list LIST_HEAD_INIT(my_list);定义时初始化与LIST_HEAD等价c复制下载// 三种方式的等价关系 LIST_HEAD(my_list); // 等价于 struct list_head my_list LIST_HEAD_INIT(my_list); // 等价于 struct list_head my_list; INIT_LIST_HEAD(my_list);八、为什么选择侵入式链表特性传统链表非侵入式Linux 侵入式链表节点包含数据节点内包含data指针数据包含list_head类型安全需要void*转换通过list_entry保证类型安全代码复用每个类型需要独立实现一套 API 适用于所有类型内存分配节点和数据分开分配一次分配缓存友好灵活性较低高同一数据可在多个链表中九、常见用法模式模式1结构体包含多个链表节点c复制下载struct task_struct { // ... struct list_head tasks; // 在全局任务链表中 struct list_head ptrace; // 在父进程的跟踪链表中 struct list_head run_list; // 在调度器运行队列中 // ... };模式2遍历并修改c复制下载// 安全遍历允许删除 struct list_head *pos, *n; list_for_each_safe(pos, n, my_list) { struct my_data *entry list_entry(pos, struct my_data, list); if (entry-id target_id) { list_del(pos); kfree(entry); } }十、总结问题答案LIST_HEAD是什么定义并初始化链表头的宏展开后是什么struct list_head name { name, name }链表头的作用作为双向循环链表的入口如何获取包含的结构体list_entry(pos, type, member)遍历用什么list_for_each()或list_for_each_safe()为什么用侵入式通用性强缓存友好一套 API 通吃一句话总结LIST_HEAD是 Linux 内核链表的起点它创建一个空的双向循环链表头配合list_entry和遍历宏构成了内核中最核心、最优雅的数据结构之一

相关新闻

太原无人机行业应用培训

太原无人机行业应用培训

近年来,随着无人机技术在航拍测绘、电力巡检、农业植保、安防救援等领域的广泛应用,具备专业技能的无人机操作人才需求日益旺盛。对于有志于投身这一行业的求职者或从业者来说,选择一家专业、正规的培训机构至关重要。本文将从行业现状、培训…

2026/10/18 15:28:11 阅读更多 →
嵌入式系统启动奥秘:深度解析TI处理器ROM Code架构与调试实战

嵌入式系统启动奥秘:深度解析TI处理器ROM Code架构与调试实战

1. 项目概述与核心价值在嵌入式系统开发中,最神秘也最关键的环节,往往不是我们精心编写的应用代码,而是芯片上电后、我们代码运行前的那“一刹那”。这个瞬间,决定了你的电路板是能亮起第一盏灯,还是永远沉寂。这个幕后…

2026/10/17 5:13:35 阅读更多 →
2026 告别充值!各大网盘怎么免费不限速解析直链下载终极指南

2026 告别充值!各大网盘怎么免费不限速解析直链下载终极指南

在日常数字生活中,网盘是文件传输的重要载体,但“限速”和“网络丢包”经常导致下载进度条卡住。本文将从网络排查、客户端设置、第三方工具辅助及网络环境调优等维度,系统化梳理网盘提速的实用策略。 https://www.pandown.orghttps://www.p…

2026/10/18 4:50:17 阅读更多 →

最新新闻

2019年CSP-S初赛选择题1-5题精讲:进制、位运算、栈、二叉树与KMP陷阱全解析

2019年CSP-S初赛选择题1-5题精讲:进制、位运算、栈、二叉树与KMP陷阱全解析

2019年的CSP-S初赛,是我第一次以“CSP”而不是“NOIP”的名义走进考场。说实话,当时心里多少有点没底——毕竟是新名字的第一年,谁也不知道命题风格会不会大改。等我翻到选择题第一页,看到前5题的时候反而松了口气:进制…

2026/10/19 3:15:05 阅读更多 →
腾讯云文本审核工具类封装实践:从SDK调用到一行接入

腾讯云文本审核工具类封装实践:从SDK调用到一行接入

做后端这几年,涉及用户输入的场景就没断过——评论、弹幕、私信、AI对话、论坛发帖,几乎每个能提交文字的地方都得过一道内容安全检查。一开始我也图省事,想着审核就审核,直接在业务代码里new一个请求对象,调一下腾讯云…

2026/10/19 3:15:05 阅读更多 →
神龙汽车新春守护直播:车企节点型用户关系运营如何落地

神龙汽车新春守护直播:车企节点型用户关系运营如何落地

看到“知音相伴 一路同行|神龙汽车‘新春守护暖心发布’专场直播即将温情启幕”这个标题时,我第一反应是:这不只是一场普通的车企直播预告,而是一个典型的“节点型用户关系运营”样本。作为一个常年做汽车品牌营销和直播策划的人&…

2026/10/19 3:15:05 阅读更多 →
JSON-RPC 2.0实战:Python实现、TCP/HTTP接入与避坑指南

JSON-RPC 2.0实战:Python实现、TCP/HTTP接入与避坑指南

简介:jsonRPC.rar是一份面向Java Web开发者的JSON-RPC入门案例资源包,集中演示了轻量级远程调用协议的基本原理与实现方式,解决分布式服务通信及前后端API交互场景中的实际搭建问题。资源共35个文件,包含25个jar依赖库&#xff08…

2026/10/19 3:15:05 阅读更多 →
TTHHO优化RBF神经网络参数:分类预测准确率突破91%的实战解析

TTHHO优化RBF神经网络参数:分类预测准确率突破91%的实战解析

如果你手头有一个分类任务,先试了试直接训练径向基函数网络(RBF),结果测试集准确率卡在八成出头再也上不去,你大概率会怀疑:是不是数据没处理好?特征选择有问题?我告诉你&#xff0c…

2026/10/19 3:15:04 阅读更多 →
Flink有界流与无界流:核心区别、运行时行为差异与选型避坑指南

Flink有界流与无界流:核心区别、运行时行为差异与选型避坑指南

1. 从一个反直觉的现象说起:为什么批处理跑得好好的,换成流处理就出问题刚接触 Flink 的人,十有八九会在某个时刻被一个看似简单的问题绊住:我明明写的是同一套算子逻辑,为什么换成流模式跑,结果要么迟迟不…

2026/10/19 3:14:03 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →