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

【Linux】内核代码阅读 list_entry()

内核代码学习

list_entry()

作用:获取ptr所属结构体的首地址

#define list_entry(ptr, type, member) \((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
// ptr:指向list_node类型的指针
// type:一个结构体
// member:结构type中的一个域

使用示例

  • ptr为head.member
  • ptr所属结构体为numlist
    • 获取ptr所属结构体的首地址也就是获取head
// 链表
struct list_node
{struct list *prev,next;
}struct numlist
{int num;struct list_node member;
};// 使用
struct numlist head;struct numlist *p = list_entry(head.member,struct numblist,member)// p 的地址就是 head 的地址
p.num;//相当于head.num

为什么这么做?

  • 因为遍历的时候是用head.member在遍历,此时是赋值给某个变量例如pos,而没有head的首地址,因为要取出num所以需要首地址

在这里插入图片描述

疑问

明明有head,为什么要用head.member去获得head的地址呢?

  • 跟遍历链表有关
    • 遍历链表是在遍历member,而此时并没有head的地址,这时候要访问head中的其他地址时则需要先获得head的首地址

例子:Linux内核模块,用以创建、增加和遍历一个双向链表

// 涉及的数据结构和宏
struct list_head{struct list_head *next,*prev;
}#define INIT_LIST_HEAD(name) {&(name),&(name)}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;
}
static inline void list_add_tail(struct list_head *new,struct list_head *head){__list_add(new,head.prev,head);
}#define list_for_each(pos,head) \for(pos = head -> next;pos!=(head);pos = pos -> next)
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/list.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("X");#define N 10 //链表节点数
struct numlist{int num; //数据struct list_head list; // 指向双向链表前后指针
}struct numlist numhead; //头节点static int __init doublelist_init(void){// 初始化头结点struct numlist *listnode;struct list_head *pos;struct numlist *p;int i;printk("doublelist is starting...\n");INIT_LIST_HEAD(&numhead.list);// 建立N个结点,依次加入到链表中for(i = 0; i < N; i++) {listnode = (struct numlist *)kmalloc(sizeof(struct numlist),GFP_KERNEL); //kmalloc()在内核空间申请内存,类似于malloclistnode.num = i +1;list_add_tail(&listnode.list,&numhead.list);printk("Node %d has added to the doublelist... \n",i+1);}// 遍历:list_entry()作用的体现list_for_each(pos,&numhead.list){// 在遍历过程中并没有获得numlist类型的地址,所以只能通过该函数来获得p = list_entry(pos,struct numlist,list);printk("Node %d's data %d\n",i,p->num);i++;}
}
解读代码
#define list_entry(ptr, type, member) \((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))list_entry(head.member,struct numblist,member)
// 即
((struct numblist *)((char *)(head.member)-(unsigned long)(&((struct numblist *)0)->member))) 

1.后面的减数

(unsigned long)(&((struct numblist *)0)->member)))
(struct numblist *)0)->member:member在struct numblist中的偏移地址

  • 例如:struct numblist node,现在要访问该结构体的member地址
    • node.member
    • 或者 &(node + (struct numblist *)0)->member)
      • 即node + (struct numblist *)0)->member是偏移量

在这里插入图片描述

((struct numblist *)((char *)(head.member)-(unsigned long)(&((struct numblist *)0)->member)))

  • 按上面的推导,即得到head.member所在的节点head的首地址

在这里插入图片描述

http://www.xdnf.cn/news/11937.html

相关文章:

  • 2022年危险化学品经营单位安全管理人员操作证考试题及在线模拟考试
  • 为找工作的同学提供一些大公司的招聘地址。都是本人花时间整理的。一定要看哟:)
  • csol什么时间服务器维护,csol6月10日服务器更新维护公告
  • 《经 典 文 章 大 赏》
  • excel使用教程_火遍全球的14个Excel学习网:大神套路、视频课、软件下载应有尽有...
  • 视频接口大全(HDMI、DVI、VGA、RGB、分量、S端子、USB接口)
  • 把CDLinux制作成U盘启动
  • 新生搜索神器Microsoft Academic Search与Google scholar、PubMed、wos、embase大PK!
  • umd格式电子书_这可能是安卓端最强的电子书阅读APP(“静读天下”使用技巧)...
  • 电子杂志制作
  • java乱码转换中文_java中文乱码解决之道(四)-java编码转换过程 - Java 技术驿站-Java 技术驿站...
  • Win7系统提示找不到AdmTmpl.dll文件的解决办法
  • 【内网提权】windows2003本地PR提权详解
  • struts2教程--快速入门
  • shutdown 命令参数介绍
  • HTML5+CSS3案例一:学成在线
  • 人工智能5:构建基于iris 数据集的 SVM 分类模型,含有 iris.csv
  • DAVINCInbsp;DM365-DM368开发攻略…
  • 【2024最新版】超详细Wireshark安装保姆级教程,及简单使用Wireshark抓包_wireshark官网
  • Dopamine(多巴胺)越狱工具一键越狱教程:支持 iOS 15-iOS 16.6.1 设备
  • 完整图书馆管理系统(包含设计思路、图形界面、后台数据库)
  • 百度二级域名大全 目前为234个http://www.twocity.cn/blog/article.asp?id=818
  • 转vmp3.0.9全保护拆分解析
  • htc G10刷机教程
  • VC 界面库皮肤库
  • 植物大战僵尸:逆向分析阳光
  • 手把手教你搭建自己的个人博客(图文教程)
  • 【零基础从入门到精通】程序、C语言
  • 千渡互通 (1000du2) V1.0 客户端 http://down.hotlife.cn/html/download/2006/6/06/1149565794.shtml
  • ASP网站漏洞解析及黑客入侵防范方法