当前位置: 首页 > news >正文

linux内核中的链表实现

linux中内核中链表的实现方式与众不同,它不是将数据结构塞入链表中,而是将链表节点塞入数据结构。
链表代码在头文件<linux/list.h>中声明,其数据结构很简单:

struct list_head{
struct list_head *next;
struct list_head * prev;
};

next指针指向下一个链表节点,pre指针指向前一个。然后,似乎这里还看不出它们有多大的作用。到底什么才是链表存储的具体内容呢?

struct fox{
unsigned long tail_length;/*尾巴长度,以厘米为单位*/
unsigned long weight:/*重量,以千克为单位*/
bool is_fantastic:
struct list_head list;/*所有fox结构体形成链表*/
}

上述结构中,fox中的list.next指向下一个元素,list.pre指向前一个元素。现在链表已经能用了,但是显然还不够方便。因此内核又提供了一组链表操作流程。比如list_add()方法加入一个新节点到链表中。但是这些方法都有一个统一的特点:他们只接受list_head 结构作为参数。使用宏container_or()我们可以很方便地从链表指针找到父结构中包含的任何变量。这是因为在C语言中,一个给定结构中的变量偏移在编译时就被ABI固定下来了。

#define container_of(ptr,type,member) ({
const typeof( (type*)0 ->member *__mptr = (ptr));
(type*) ( (char*)__mptr - offsetof(type,member); );
})

核心作用是从一个结构体(struct)中某个成员的指针,计算出整个结构体的起始地址(指针)。这在处理复杂数据结构如链表、树或内核对象时非常有用,因为它允许你通过成员字段直接访问整个容器结构。

作用详解:
宏的功能:给定一个指向结构体成员的指针(ptr),结构体的类型(type),以及成员的名称(member),这个宏能返回一个指向整个结构体的指针。简单说,就是“通过成员找容器”。
为什么需要它:在C语言中,结构体成员在内存中是连续存储的。如果你只有某个成员的地址(比如链表节点的指针),但需要访问整个结构体(比如包含链表节点的数据结构),这个宏能快速计算出偏移量并定位到起始位置。

宏的解析(逐部分解释):

#define container_of(ptr, type, member) ({const typeof( ((type *)0)->member ) *__mptr = (ptr); // 步骤1: 定义临时指针变量(type *)( (char *)__mptr - offsetof(type, member) ); // 步骤2: 计算并转换地址
})

1、const typeof( ((type *)0)->member ) *__mptr = (ptr);: • ((type *)0)->member:这是一个技巧,它模拟一个指向type类型结构体的空指针(0地址),并访问其member成员。这样就能获取member的类型(使用typeof)。 • typeof(…):在编译时获取成员的类型,确保类型安全。 • *__mptr = (ptr):定义一个临时指针变量__mptr,赋值为传入的ptr(成员指针)。const修饰确保变量不被修改。
2. (type *)( (char *)__mptr - offsetof(type, member) );: • offsetof(type, member):这是一个标准宏(通常在stddef.h中定义),计算成员member在结构体type中的字节偏移量。 • (char *)__mptr:将成员指针转换为char *类型,因为偏移量是以字节为单位的,这样可以进行精确的指针算术。 • (char *)__mptr - offsetof(type, member):从成员指针减去偏移量,得到整个结构体的起始地址。 • (type *):最后将地址强制转换为指向type类型的指针,这样你就可以直接使用这个指针访问结构体的其他字段。

struct person {
int age;
char name[20];
struct list_head list; // 假设这是一个链表节点成员
};
• 如果有一个list_head *ptr指向person结构体中的list成员。 • 使用container_of(ptr, struct person, list): ◦ 计算list在struct person中的偏移量(比如8字节)。 ◦ 从ptr减去8字节,得到struct person的起始地址。 ◦ 这样,你就可以访问整个person结构体,如person_ptr->age或person_ptr->name。 优势与注意事项: • 优势:高效、类型安全,避免了手动计算偏移量的错误,常用于内核或嵌入式开发。 • 注意事项:这个宏依赖于GNU C扩展(如typeof和({…})语法),所以在非GCC编译器中可能不可用。使用时确保参数正确,否则会导致未定义行为(如野指针)。

http://www.lqws.cn/news/514711.html

相关文章:

  • sentinel与seata组件在微服务中的基本作用
  • 微信点餐小程序—美食物
  • ICML 2025 | 低秩Swish网络:理论突破实现高效逼近,小模型性能媲美大网络
  • CSP - J 400分题单总结(洛谷题号)
  • 通过 HTML 子图和多尺度卷积 BERT 的双向融合实现可解释的恶意 URL 检测
  • xtrabackup 的工作原理 为什么不用停服?
  • Jenkins Pipeline 与 Python 脚本之间使用环境变量通信
  • IDEA高效开发指南:JRebel热部署
  • 设计模式精讲 Day 13:责任链模式(Chain of Responsibility Pattern)
  • 激光束修复手机屏任意层不良区域,实现液晶线路激光修复原理
  • 鸿蒙与h5的交互
  • AR美型SDK,重塑面部美学,开启智能美颜新纪元
  • 微信小程序适配 iPhone 底部导航区域(safe area)的完整指南
  • 【JAVA】idea中打成jar包后报错错误: 找不到或无法加载主类
  • 大学专业科普 | 物联网、自动化和人工智能
  • IO多路复用——Poll底层原理深度分析
  • 深入解析RS485通信:从原理到Linux驱动开发实践
  • DeepSeek在数据分析与科学计算中的革命性应用
  • “易问易视”——让数据分析像聊天一样简单
  • 终止分区表变更操作时误删数据字典缓存导致MySQL崩溃分析
  • 【网站内容安全检测】之2:从网站所有URL页面中提取所有外部及内部域名信息
  • 批量DWG转PDF工具
  • 提供一种在树莓派5上切换模式的思路(本文是面向显示屏配置文件)
  • LVS-DR负载均衡群集深度实践:高性能架构设计与排障指南
  • BUUCTF在线评测-练习场-WebCTF习题[ACTF2020 新生赛]BackupFile1-flag获取、解析
  • 一款实验室创客实验室用的桌面式五轴加工中心
  • 04-html元素列表-表格-表单
  • django request.data.get 判断有没有 某个参数
  • GROUP BY、UNION和COALESCE协作
  • 电商导购app平台的缓存策略与性能优化方案:架构师的实践经验