内核链表中的container_of和list_entryg

本文深入探讨了Linux内核中的链表结构及其操作方法,特别是通过对container_of宏的解析,揭示了如何从链表节点指针定位到包含该节点的实际结构体。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BBBc

最近一直在读LINUX内核设计与实现,之前自己用C写过单链表的实现,读到第六章内核数据结构时,大感亲切,不似前章晦涩。内核链表结构的所有操作只接受list_head类型的数据作为参数,并依靠list_entry来完成链表的各种管理,读到这里,我想起第三章进程管理中current宏获取当前进程tpid(因为线程组号tpid和进程pid相同)中,在遍历进程时用到的list_entry获取下一个进程:

list_entry(task->tasks.next,struct task_struct,task)

我发现在第六章通过宏定义将list_entry定义成container_of,追踪container_of宏

  1. /** 
  2. * container_of - cast a member of a structure out to the containing structure 
  3. * @ptr:    the pointer to the member. 
  4. * @type:   the type of the container struct this is embedded in. 
  5. * @member: the name of the member within the struct. 
  6. * */  
  7.   
  8. #define container_of(ptr, type, member) ({                    /          
  9.         const typeof( ((type *)0)->member ) *__mptr = (ptr); -/  
  10.         (type *)( (char *)__mptr - offsetof(type,member) );})


这里的(type *)0使用的是虚拟结构,也就是将结构体首地址设为0,这样 ((type *) 0)->member指向的地址就是相对于首地址的偏移量!同时mptr初始化为ptr,这样mptr减去member的偏移地址就能得到ptr结构体的首地址。我在网上找到另一种写法:

        #define list_entry(ptr, type, member) /
                ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

所以本意上,container_of和list_entry的作用是一样,都得到当前指向的结构体的地址,这样就能取到这个结构体内的任何成员变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值