You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核container_of宏解析:指针与链表应用疑问

关于Linux内核container_of宏的两个核心疑问解答

1. ((type *)0)->member 的作用

这个写法是编译期类型校验的手段,不会触发实际内存访问(仅做语法层面的类型推导,运行时不会真的读取地址0的数据)。

它的核心目的是配合static_assert,确保传入container_of的ptr指针,指向的成员类型和外层结构体type中member成员的类型完全匹配:

  • ((type *)0) 是把地址0强制转换成type类型的指针,相当于虚拟出一个type结构体实例在地址0处
  • ->member 引用这个虚拟实例的member成员,编译器会推导出该成员的类型
  • 再通过__same_type宏对比*(ptr)和这个成员的类型,不匹配就触发编译报错,避免传入错误类型指针导致后续地址计算出错

2. __mptr - offsetof(type, member) 的实现原理及链表场景应用

原理部分

  • offsetof(type, member) 是编译器内置(或内核实现)的宏,用来计算member成员在type结构体中的字节偏移量(从结构体起始地址到该成员的字节数)
  • __mptr 是ptr转换后的void*指针,指向member成员的实际内存地址
  • 用成员地址减去它在结构体中的偏移量,得到的就是外层type结构体的起始地址,再强制转换成type*类型,就拿到了外层结构体的指针

链表场景(以sk_buff为例)

Linux内核双向链表通过list_head结构体实现,它仅保存next、prev指针,不关联具体业务结构体。在sk_buff中,list是嵌入的list_head成员:

  • 维护链表时,只需操作list_head的指针(比如list_add、list_del等链表API),无需关心外层sk_buff
  • 当需要从链表节点反向获取sk_buff时,就用container_of:假设拿到某个list_head的指针p_list,调用container_of(p_list, struct sk_buff, list),就会计算出该list成员对应的sk_buff起始地址,从而拿到完整的sk_buff指针,方便操作协议头、数据等其他成员

实际遍历示例:

struct list_head *pos;
struct sk_buff *skb;

list_for_each(pos, &skb_list_head) {
    skb = container_of(pos, struct sk_buff, list);
    // 此处可操作skb的其他成员,比如skb->data
}

内容的提问来源于stack exchange,提问作者ca-hercor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:55:23