Linux 系统内核列表宏解析

Linux 系统内核列表宏深度解析

0. 引言

在 Linux 内核中,链表是使用最广泛的数据结构之一。从进程管理到设备驱动,从内存管理到文件系统,几乎每个子系统都离不开链表的身影。Linux 内核链表的设计堪称经典,它通过侵入式设计宏定义实现了类型无关的通用链表操作,这种设计思想值得每一位系统级程序员深入学习和掌握。

本文目标读者

  • 嵌入式 Linux 开发者
  • 内核驱动工程师
  • 对数据结构设计感兴趣的 C 语言程序员
  • 希望深入理解 Linux 内核设计思想的学习者

本文学习目标

  • 理解 Linux 内核链表的设计原理
  • 掌握核心宏的使用方法
  • 了解与传统链表的差异和优势
  • 学会避免常见的使用陷阱

1. Linux 链表是如何做到类型无关的?

1.1 核心数据结构:list_head

传统链表通常将数据和指针放在一起,而 Linux 内核采用了侵入式设计------将链表节点嵌入到数据结构体中:

c 复制代码
struct list_head {
    struct list_head *next, *prev;  // 仅包含双向指针,无数据域
};

设计精髓list_head 不包含任何业务数据,它只是一个纯粹的链表节点。这种设计使得同一套链表操作可以应用于任意结构体。

1.2 与传统链表的对比

特性 传统链表 Linux 内核链表
结构设计 数据 + 指针 仅指针,数据通过偏移计算获取
类型依赖 每种数据类型需单独实现链表 一套宏支持所有类型
内存开销 每个节点额外分配指针结构体 零额外开销
灵活性 一个结构体只能属于一个链表 可嵌入多个 list_head
缓存友好 数据和指针分离存储 数据和指针连续存储

1.3 内存布局示意

复制代码
传统链表布局:
┌─────────────┐    ┌─────────────┐
│ data1       │    │ data2       │
├─────────────┤    ├─────────────┤
│ next ───────┼───>│ next ───────┼───> NULL
│ prev ───────┼───>│ prev ───────┼───> ...
└─────────────┘    └─────────────┘

Linux链表布局:
┌─────────────────────────────┐
│ struct student              │
│   int id;                   │
│   char name[20];            │
│   int age;                  │
│   struct list_head list;    │<─── 嵌入的链表节点
│       list.next ────────────┼───> 下一个节点的 list
│       list.prev ────────────┼───> 上一个节点的 list
└─────────────────────────────┘

思考题 :如果 list_head 不是结构体的第一个成员,list_entry 宏是否依然有效?为什么?


2. 核心操作宏详解与使用场景

2.1 完整的 list.h 实现

c 复制代码
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H

// 核心链表节点结构
struct list_head {
    struct list_head *next, *prev;
};

// 静态初始化:编译期将 next/prev 指向自身(空链表状态)
#define LIST_HEAD_INIT(name) { &(name), &(name) }

// 声明并初始化链表头变量
#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)

// 动态初始化:运行时初始化链表节点
static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}

// 【核心】内部插入函数:在 prev 和 next 之间插入 new
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;
}

// 头部插入:在 head 之后插入(适用于栈式操作)
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

// 尾部插入:在 head 之前插入(适用于队列式操作)
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
    __list_add(new, head->prev, head);
}

// 【核心】内部删除函数
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
    next->prev = prev;
    prev->next = next;
}

// 删除节点:将节点从链表中移除并清空指针
static inline void list_del(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    entry->next = (void *)0;  // 标记为已删除
    entry->prev = (void *)0;
}

// 判断链表是否为空
static inline int list_empty(const struct list_head *head)
{
    return head->next == head;
}

// 【核心中的核心】从链表节点指针获取容器结构体指针
#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

// 获取链表第一个元素
#define list_first_entry(ptr, type, member) \
    list_entry((ptr)->next, type, member)

// 获取链表最后一个元素
#define list_last_entry(ptr, type, member) \
    list_entry((ptr)->prev, type, member)

// 遍历链表节点(不支持删除)
#define list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)

// 【安全遍历】遍历链表节点(支持删除操作)
#define list_for_each_safe(pos, n, head) \
    for (pos = (head)->next, n = pos->next; pos != (head); \
         pos = n, n = pos->next)

// 遍历并直接获取结构体指针
#define list_for_each_entry(pos, head, member) \
    for (pos = list_first_entry(head, typeof(*pos), member); \
         &pos->member != (head); \
         pos = list_next_entry(pos, member))

// 获取下一个结构体元素
#define list_next_entry(pos, member) \
    list_entry((pos)->member.next, typeof(*(pos)), member)

#endif

2.2 插入操作图解(Mermaid)

插入前状态
#mermaid-svg-PLRCyy37l5uVtmwE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PLRCyy37l5uVtmwE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PLRCyy37l5uVtmwE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PLRCyy37l5uVtmwE .error-icon{fill:#552222;}#mermaid-svg-PLRCyy37l5uVtmwE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PLRCyy37l5uVtmwE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PLRCyy37l5uVtmwE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PLRCyy37l5uVtmwE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PLRCyy37l5uVtmwE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PLRCyy37l5uVtmwE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PLRCyy37l5uVtmwE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PLRCyy37l5uVtmwE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PLRCyy37l5uVtmwE .marker.cross{stroke:#333333;}#mermaid-svg-PLRCyy37l5uVtmwE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PLRCyy37l5uVtmwE p{margin:0;}#mermaid-svg-PLRCyy37l5uVtmwE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PLRCyy37l5uVtmwE .cluster-label text{fill:#333;}#mermaid-svg-PLRCyy37l5uVtmwE .cluster-label span{color:#333;}#mermaid-svg-PLRCyy37l5uVtmwE .cluster-label span p{background-color:transparent;}#mermaid-svg-PLRCyy37l5uVtmwE .label text,#mermaid-svg-PLRCyy37l5uVtmwE span{fill:#333;color:#333;}#mermaid-svg-PLRCyy37l5uVtmwE .node rect,#mermaid-svg-PLRCyy37l5uVtmwE .node circle,#mermaid-svg-PLRCyy37l5uVtmwE .node ellipse,#mermaid-svg-PLRCyy37l5uVtmwE .node polygon,#mermaid-svg-PLRCyy37l5uVtmwE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PLRCyy37l5uVtmwE .rough-node .label text,#mermaid-svg-PLRCyy37l5uVtmwE .node .label text,#mermaid-svg-PLRCyy37l5uVtmwE .image-shape .label,#mermaid-svg-PLRCyy37l5uVtmwE .icon-shape .label{text-anchor:middle;}#mermaid-svg-PLRCyy37l5uVtmwE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PLRCyy37l5uVtmwE .rough-node .label,#mermaid-svg-PLRCyy37l5uVtmwE .node .label,#mermaid-svg-PLRCyy37l5uVtmwE .image-shape .label,#mermaid-svg-PLRCyy37l5uVtmwE .icon-shape .label{text-align:center;}#mermaid-svg-PLRCyy37l5uVtmwE .node.clickable{cursor:pointer;}#mermaid-svg-PLRCyy37l5uVtmwE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PLRCyy37l5uVtmwE .arrowheadPath{fill:#333333;}#mermaid-svg-PLRCyy37l5uVtmwE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PLRCyy37l5uVtmwE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PLRCyy37l5uVtmwE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PLRCyy37l5uVtmwE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PLRCyy37l5uVtmwE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PLRCyy37l5uVtmwE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PLRCyy37l5uVtmwE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PLRCyy37l5uVtmwE .cluster text{fill:#333;}#mermaid-svg-PLRCyy37l5uVtmwE .cluster span{color:#333;}#mermaid-svg-PLRCyy37l5uVtmwE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PLRCyy37l5uVtmwE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PLRCyy37l5uVtmwE rect.text{fill:none;stroke-width:0;}#mermaid-svg-PLRCyy37l5uVtmwE .icon-shape,#mermaid-svg-PLRCyy37l5uVtmwE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PLRCyy37l5uVtmwE .icon-shape p,#mermaid-svg-PLRCyy37l5uVtmwE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PLRCyy37l5uVtmwE .icon-shape .label rect,#mermaid-svg-PLRCyy37l5uVtmwE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PLRCyy37l5uVtmwE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PLRCyy37l5uVtmwE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PLRCyy37l5uVtmwE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} head
node1

插入后状态(list_add - 头部插入)
#mermaid-svg-DRXywbvYJC8KX341{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DRXywbvYJC8KX341 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DRXywbvYJC8KX341 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DRXywbvYJC8KX341 .error-icon{fill:#552222;}#mermaid-svg-DRXywbvYJC8KX341 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DRXywbvYJC8KX341 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DRXywbvYJC8KX341 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DRXywbvYJC8KX341 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DRXywbvYJC8KX341 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DRXywbvYJC8KX341 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DRXywbvYJC8KX341 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DRXywbvYJC8KX341 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DRXywbvYJC8KX341 .marker.cross{stroke:#333333;}#mermaid-svg-DRXywbvYJC8KX341 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DRXywbvYJC8KX341 p{margin:0;}#mermaid-svg-DRXywbvYJC8KX341 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DRXywbvYJC8KX341 .cluster-label text{fill:#333;}#mermaid-svg-DRXywbvYJC8KX341 .cluster-label span{color:#333;}#mermaid-svg-DRXywbvYJC8KX341 .cluster-label span p{background-color:transparent;}#mermaid-svg-DRXywbvYJC8KX341 .label text,#mermaid-svg-DRXywbvYJC8KX341 span{fill:#333;color:#333;}#mermaid-svg-DRXywbvYJC8KX341 .node rect,#mermaid-svg-DRXywbvYJC8KX341 .node circle,#mermaid-svg-DRXywbvYJC8KX341 .node ellipse,#mermaid-svg-DRXywbvYJC8KX341 .node polygon,#mermaid-svg-DRXywbvYJC8KX341 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DRXywbvYJC8KX341 .rough-node .label text,#mermaid-svg-DRXywbvYJC8KX341 .node .label text,#mermaid-svg-DRXywbvYJC8KX341 .image-shape .label,#mermaid-svg-DRXywbvYJC8KX341 .icon-shape .label{text-anchor:middle;}#mermaid-svg-DRXywbvYJC8KX341 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DRXywbvYJC8KX341 .rough-node .label,#mermaid-svg-DRXywbvYJC8KX341 .node .label,#mermaid-svg-DRXywbvYJC8KX341 .image-shape .label,#mermaid-svg-DRXywbvYJC8KX341 .icon-shape .label{text-align:center;}#mermaid-svg-DRXywbvYJC8KX341 .node.clickable{cursor:pointer;}#mermaid-svg-DRXywbvYJC8KX341 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DRXywbvYJC8KX341 .arrowheadPath{fill:#333333;}#mermaid-svg-DRXywbvYJC8KX341 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DRXywbvYJC8KX341 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DRXywbvYJC8KX341 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DRXywbvYJC8KX341 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DRXywbvYJC8KX341 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DRXywbvYJC8KX341 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DRXywbvYJC8KX341 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DRXywbvYJC8KX341 .cluster text{fill:#333;}#mermaid-svg-DRXywbvYJC8KX341 .cluster span{color:#333;}#mermaid-svg-DRXywbvYJC8KX341 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DRXywbvYJC8KX341 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DRXywbvYJC8KX341 rect.text{fill:none;stroke-width:0;}#mermaid-svg-DRXywbvYJC8KX341 .icon-shape,#mermaid-svg-DRXywbvYJC8KX341 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DRXywbvYJC8KX341 .icon-shape p,#mermaid-svg-DRXywbvYJC8KX341 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DRXywbvYJC8KX341 .icon-shape .label rect,#mermaid-svg-DRXywbvYJC8KX341 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DRXywbvYJC8KX341 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DRXywbvYJC8KX341 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DRXywbvYJC8KX341 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} head
new
node1

插入后状态(list_add_tail - 尾部插入)
#mermaid-svg-xvDSUhE3DTOlvE6V{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xvDSUhE3DTOlvE6V .error-icon{fill:#552222;}#mermaid-svg-xvDSUhE3DTOlvE6V .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xvDSUhE3DTOlvE6V .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xvDSUhE3DTOlvE6V .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xvDSUhE3DTOlvE6V .marker.cross{stroke:#333333;}#mermaid-svg-xvDSUhE3DTOlvE6V svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xvDSUhE3DTOlvE6V p{margin:0;}#mermaid-svg-xvDSUhE3DTOlvE6V .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xvDSUhE3DTOlvE6V .cluster-label text{fill:#333;}#mermaid-svg-xvDSUhE3DTOlvE6V .cluster-label span{color:#333;}#mermaid-svg-xvDSUhE3DTOlvE6V .cluster-label span p{background-color:transparent;}#mermaid-svg-xvDSUhE3DTOlvE6V .label text,#mermaid-svg-xvDSUhE3DTOlvE6V span{fill:#333;color:#333;}#mermaid-svg-xvDSUhE3DTOlvE6V .node rect,#mermaid-svg-xvDSUhE3DTOlvE6V .node circle,#mermaid-svg-xvDSUhE3DTOlvE6V .node ellipse,#mermaid-svg-xvDSUhE3DTOlvE6V .node polygon,#mermaid-svg-xvDSUhE3DTOlvE6V .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xvDSUhE3DTOlvE6V .rough-node .label text,#mermaid-svg-xvDSUhE3DTOlvE6V .node .label text,#mermaid-svg-xvDSUhE3DTOlvE6V .image-shape .label,#mermaid-svg-xvDSUhE3DTOlvE6V .icon-shape .label{text-anchor:middle;}#mermaid-svg-xvDSUhE3DTOlvE6V .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xvDSUhE3DTOlvE6V .rough-node .label,#mermaid-svg-xvDSUhE3DTOlvE6V .node .label,#mermaid-svg-xvDSUhE3DTOlvE6V .image-shape .label,#mermaid-svg-xvDSUhE3DTOlvE6V .icon-shape .label{text-align:center;}#mermaid-svg-xvDSUhE3DTOlvE6V .node.clickable{cursor:pointer;}#mermaid-svg-xvDSUhE3DTOlvE6V .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xvDSUhE3DTOlvE6V .arrowheadPath{fill:#333333;}#mermaid-svg-xvDSUhE3DTOlvE6V .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xvDSUhE3DTOlvE6V .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xvDSUhE3DTOlvE6V .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xvDSUhE3DTOlvE6V .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xvDSUhE3DTOlvE6V .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xvDSUhE3DTOlvE6V .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xvDSUhE3DTOlvE6V .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xvDSUhE3DTOlvE6V .cluster text{fill:#333;}#mermaid-svg-xvDSUhE3DTOlvE6V .cluster span{color:#333;}#mermaid-svg-xvDSUhE3DTOlvE6V div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xvDSUhE3DTOlvE6V .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xvDSUhE3DTOlvE6V rect.text{fill:none;stroke-width:0;}#mermaid-svg-xvDSUhE3DTOlvE6V .icon-shape,#mermaid-svg-xvDSUhE3DTOlvE6V .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xvDSUhE3DTOlvE6V .icon-shape p,#mermaid-svg-xvDSUhE3DTOlvE6V .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xvDSUhE3DTOlvE6V .icon-shape .label rect,#mermaid-svg-xvDSUhE3DTOlvE6V .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xvDSUhE3DTOlvE6V .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xvDSUhE3DTOlvE6V .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xvDSUhE3DTOlvE6V :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} head
node1
new

插入流程图
#mermaid-svg-C9VSt12B3zxvQa8j{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-C9VSt12B3zxvQa8j .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-C9VSt12B3zxvQa8j .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-C9VSt12B3zxvQa8j .error-icon{fill:#552222;}#mermaid-svg-C9VSt12B3zxvQa8j .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-C9VSt12B3zxvQa8j .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-C9VSt12B3zxvQa8j .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-C9VSt12B3zxvQa8j .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-C9VSt12B3zxvQa8j .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-C9VSt12B3zxvQa8j .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-C9VSt12B3zxvQa8j .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-C9VSt12B3zxvQa8j .marker{fill:#333333;stroke:#333333;}#mermaid-svg-C9VSt12B3zxvQa8j .marker.cross{stroke:#333333;}#mermaid-svg-C9VSt12B3zxvQa8j svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-C9VSt12B3zxvQa8j p{margin:0;}#mermaid-svg-C9VSt12B3zxvQa8j .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-C9VSt12B3zxvQa8j .cluster-label text{fill:#333;}#mermaid-svg-C9VSt12B3zxvQa8j .cluster-label span{color:#333;}#mermaid-svg-C9VSt12B3zxvQa8j .cluster-label span p{background-color:transparent;}#mermaid-svg-C9VSt12B3zxvQa8j .label text,#mermaid-svg-C9VSt12B3zxvQa8j span{fill:#333;color:#333;}#mermaid-svg-C9VSt12B3zxvQa8j .node rect,#mermaid-svg-C9VSt12B3zxvQa8j .node circle,#mermaid-svg-C9VSt12B3zxvQa8j .node ellipse,#mermaid-svg-C9VSt12B3zxvQa8j .node polygon,#mermaid-svg-C9VSt12B3zxvQa8j .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-C9VSt12B3zxvQa8j .rough-node .label text,#mermaid-svg-C9VSt12B3zxvQa8j .node .label text,#mermaid-svg-C9VSt12B3zxvQa8j .image-shape .label,#mermaid-svg-C9VSt12B3zxvQa8j .icon-shape .label{text-anchor:middle;}#mermaid-svg-C9VSt12B3zxvQa8j .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-C9VSt12B3zxvQa8j .rough-node .label,#mermaid-svg-C9VSt12B3zxvQa8j .node .label,#mermaid-svg-C9VSt12B3zxvQa8j .image-shape .label,#mermaid-svg-C9VSt12B3zxvQa8j .icon-shape .label{text-align:center;}#mermaid-svg-C9VSt12B3zxvQa8j .node.clickable{cursor:pointer;}#mermaid-svg-C9VSt12B3zxvQa8j .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-C9VSt12B3zxvQa8j .arrowheadPath{fill:#333333;}#mermaid-svg-C9VSt12B3zxvQa8j .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-C9VSt12B3zxvQa8j .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-C9VSt12B3zxvQa8j .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C9VSt12B3zxvQa8j .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-C9VSt12B3zxvQa8j .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C9VSt12B3zxvQa8j .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-C9VSt12B3zxvQa8j .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-C9VSt12B3zxvQa8j .cluster text{fill:#333;}#mermaid-svg-C9VSt12B3zxvQa8j .cluster span{color:#333;}#mermaid-svg-C9VSt12B3zxvQa8j div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-C9VSt12B3zxvQa8j .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-C9VSt12B3zxvQa8j rect.text{fill:none;stroke-width:0;}#mermaid-svg-C9VSt12B3zxvQa8j .icon-shape,#mermaid-svg-C9VSt12B3zxvQa8j .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-C9VSt12B3zxvQa8j .icon-shape p,#mermaid-svg-C9VSt12B3zxvQa8j .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-C9VSt12B3zxvQa8j .icon-shape .label rect,#mermaid-svg-C9VSt12B3zxvQa8j .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-C9VSt12B3zxvQa8j .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-C9VSt12B3zxvQa8j .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-C9VSt12B3zxvQa8j :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 开始
调用 list_add new head
获取 head->next
调用 __list_add new head head->next
设置 next->prev = new
设置 new->next = next
设置 new->prev = prev
设置 prev->next = new
结束

2.3 删除操作图解

#mermaid-svg-FX7usl6fHnb47dAc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FX7usl6fHnb47dAc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FX7usl6fHnb47dAc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FX7usl6fHnb47dAc .error-icon{fill:#552222;}#mermaid-svg-FX7usl6fHnb47dAc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FX7usl6fHnb47dAc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FX7usl6fHnb47dAc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FX7usl6fHnb47dAc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FX7usl6fHnb47dAc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FX7usl6fHnb47dAc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FX7usl6fHnb47dAc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FX7usl6fHnb47dAc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FX7usl6fHnb47dAc .marker.cross{stroke:#333333;}#mermaid-svg-FX7usl6fHnb47dAc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FX7usl6fHnb47dAc p{margin:0;}#mermaid-svg-FX7usl6fHnb47dAc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FX7usl6fHnb47dAc .cluster-label text{fill:#333;}#mermaid-svg-FX7usl6fHnb47dAc .cluster-label span{color:#333;}#mermaid-svg-FX7usl6fHnb47dAc .cluster-label span p{background-color:transparent;}#mermaid-svg-FX7usl6fHnb47dAc .label text,#mermaid-svg-FX7usl6fHnb47dAc span{fill:#333;color:#333;}#mermaid-svg-FX7usl6fHnb47dAc .node rect,#mermaid-svg-FX7usl6fHnb47dAc .node circle,#mermaid-svg-FX7usl6fHnb47dAc .node ellipse,#mermaid-svg-FX7usl6fHnb47dAc .node polygon,#mermaid-svg-FX7usl6fHnb47dAc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FX7usl6fHnb47dAc .rough-node .label text,#mermaid-svg-FX7usl6fHnb47dAc .node .label text,#mermaid-svg-FX7usl6fHnb47dAc .image-shape .label,#mermaid-svg-FX7usl6fHnb47dAc .icon-shape .label{text-anchor:middle;}#mermaid-svg-FX7usl6fHnb47dAc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FX7usl6fHnb47dAc .rough-node .label,#mermaid-svg-FX7usl6fHnb47dAc .node .label,#mermaid-svg-FX7usl6fHnb47dAc .image-shape .label,#mermaid-svg-FX7usl6fHnb47dAc .icon-shape .label{text-align:center;}#mermaid-svg-FX7usl6fHnb47dAc .node.clickable{cursor:pointer;}#mermaid-svg-FX7usl6fHnb47dAc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FX7usl6fHnb47dAc .arrowheadPath{fill:#333333;}#mermaid-svg-FX7usl6fHnb47dAc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FX7usl6fHnb47dAc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FX7usl6fHnb47dAc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FX7usl6fHnb47dAc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FX7usl6fHnb47dAc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FX7usl6fHnb47dAc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FX7usl6fHnb47dAc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FX7usl6fHnb47dAc .cluster text{fill:#333;}#mermaid-svg-FX7usl6fHnb47dAc .cluster span{color:#333;}#mermaid-svg-FX7usl6fHnb47dAc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FX7usl6fHnb47dAc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FX7usl6fHnb47dAc rect.text{fill:none;stroke-width:0;}#mermaid-svg-FX7usl6fHnb47dAc .icon-shape,#mermaid-svg-FX7usl6fHnb47dAc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FX7usl6fHnb47dAc .icon-shape p,#mermaid-svg-FX7usl6fHnb47dAc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FX7usl6fHnb47dAc .icon-shape .label rect,#mermaid-svg-FX7usl6fHnb47dAc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FX7usl6fHnb47dAc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FX7usl6fHnb47dAc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FX7usl6fHnb47dAc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 开始
调用 list_del entry
获取 entry->prev 和 entry->next
调用 __list_del prev next
设置 next->prev = prev
设置 prev->next = next
设置 entry->next = NULL
设置 entry->prev = NULL
结束

2.4 list_entry 宏的内存计算原理

这是整个链表实现中最精妙的部分:

c 复制代码
#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

计算过程图解

复制代码
内存地址: 0x00000000 (虚拟地址 0)
假设 struct student 布局:
┌────────────────────────────────┐
│ 0x00000000: int id;           │  offset = 0
├────────────────────────────────┤
│ 0x00000004: char name[20];    │  offset = 4
├────────────────────────────────┤
│ 0x00000018: int age;          │  offset = 24
├────────────────────────────────┤
│ 0x0000001C: struct list_head; │  offset = 28
│     next;                     │
│     prev;                     │
└────────────────────────────────┘

&((struct student *)0)->list = 0x1C (十进制 28)

当 ptr = &student->list = 0x1000001C 时:
结构体起始地址 = 0x1000001C - 28 = 0x10000000

原理说明

  1. (type *)0:将地址 0 强制转换为 type 类型指针
  2. &((type *)0)->member:计算 member 字段相对于结构体起始地址的偏移量
  3. (char *)(ptr) - offset:用链表节点地址减去偏移量,得到结构体起始地址

3. 实战示例:从学生管理到多链表场景

3.1 基础示例:学生信息管理

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include "list.h"

// 定义包含链表节点的结构体
struct student {
    int id;
    char name[20];
    int age;
    struct list_head list;  // 嵌入链表节点
};

void print_student(struct student *s) {
    printf("ID: %d, Name: %s, Age: %d\n", s->id, s->name, s->age);
}

int main(void) {
    // 创建链表头
    LIST_HEAD(student_list);
    
    // 创建学生节点
    struct student *s1 = malloc(sizeof(struct student));
    s1->id = 1;
    snprintf(s1->name, sizeof(s1->name), "ZhangSan");
    s1->age = 20;
    INIT_LIST_HEAD(&s1->list);  // 必须初始化!
    
    struct student *s2 = malloc(sizeof(struct student));
    s2->id = 2;
    snprintf(s2->name, sizeof(s2->name), "LiSi");
    s2->age = 21;
    INIT_LIST_HEAD(&s2->list);
    
    struct student *s3 = malloc(sizeof(struct student));
    s3->id = 3;
    snprintf(s3->name, sizeof(s3->name), "WangWu");
    s3->age = 22;
    INIT_LIST_HEAD(&s3->list);

    // 插入节点
    list_add(&s1->list, &student_list);   // 插入头部
    list_add(&s2->list, &student_list);   // 插入头部(现在在 s1 前面)
    list_add_tail(&s3->list, &student_list);  // 插入尾部

    // 遍历链表
    printf("=== 遍历链表 ===\n");
    struct student *stu;
    list_for_each_entry(stu, &student_list, list) {
        print_student(stu);
    }

    // 删除节点
    printf("\n=== 删除 ID=2 的学生 ===\n");
    list_for_each_entry(stu, &student_list, list) {
        if (stu->id == 2) {
            list_del(&stu->list);
            free(stu);
            break;
        }
    }

    // 再次遍历
    printf("\n=== 删除后的链表 ===\n");
    list_for_each_entry(stu, &student_list, list) {
        print_student(stu);
    }

    // 清理资源
    list_del(&s1->list);
    free(s1);
    list_del(&s3->list);
    free(s3);

    return 0;
}

3.2 进阶示例:多链表管理(进程控制块场景)

在实际内核场景中,一个结构体可能需要同时属于多个链表。例如进程控制块可能需要按优先级、状态等多个维度组织:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include "list.h"

// 模拟进程控制块结构
struct task_struct {
    int pid;                // 进程ID
    char comm[16];          // 进程名
    int priority;           // 优先级
    int state;              // 状态: 0=运行, 1=睡眠, 2=僵尸
    
    // 多链表节点
    struct list_head task_list;     // 所有进程链表
    struct list_head run_list;      // 运行队列
    struct list_head wait_list;     // 等待队列
};

// 全局链表头
LIST_HEAD(all_tasks);
LIST_HEAD(running_tasks);
LIST_HEAD(waiting_tasks);

void print_task(struct task_struct *task) {
    const char *state_str[] = {"RUNNING", "SLEEPING", "ZOMBIE"};
    printf("PID: %d, Name: %s, Priority: %d, State: %s\n",
           task->pid, task->comm, task->priority, state_str[task->state]);
}

int main(void) {
    // 创建进程
    struct task_struct *init = malloc(sizeof(struct task_struct));
    init->pid = 1;
    snprintf(init->comm, sizeof(init->comm), "init");
    init->priority = 100;
    init->state = 0;  // RUNNING
    INIT_LIST_HEAD(&init->task_list);
    INIT_LIST_HEAD(&init->run_list);
    INIT_LIST_HEAD(&init->wait_list);

    struct task_struct *bash = malloc(sizeof(struct task_struct));
    bash->pid = 2;
    snprintf(bash->comm, sizeof(bash->comm), "bash");
    bash->priority = 50;
    bash->state = 0;  // RUNNING
    INIT_LIST_HEAD(&bash->task_list);
    INIT_LIST_HEAD(&bash->run_list);
    INIT_LIST_HEAD(&bash->wait_list);

    struct task_struct *sleeping = malloc(sizeof(struct task_struct));
    sleeping->pid = 3;
    snprintf(sleeping->comm, sizeof(sleeping->comm), "sleep");
    sleeping->priority = 30;
    sleeping->state = 1;  // SLEEPING
    INIT_LIST_HEAD(&sleeping->task_list);
    INIT_LIST_HEAD(&sleeping->run_list);
    INIT_LIST_HEAD(&sleeping->wait_list);

    // 加入多个链表
    list_add_tail(&init->task_list, &all_tasks);
    list_add_tail(&bash->task_list, &all_tasks);
    list_add_tail(&sleeping->task_list, &all_tasks);

    list_add_tail(&init->run_list, &running_tasks);
    list_add_tail(&bash->run_list, &running_tasks);
    
    list_add_tail(&sleeping->wait_list, &waiting_tasks);

    // 遍历所有进程
    printf("=== 所有进程 ===\n");
    struct task_struct *task;
    list_for_each_entry(task, &all_tasks, task_list) {
        print_task(task);
    }

    // 遍历运行队列
    printf("\n=== 运行队列 ===\n");
    list_for_each_entry(task, &running_tasks, run_list) {
        print_task(task);
    }

    // 遍历等待队列
    printf("\n=== 等待队列 ===\n");
    list_for_each_entry(task, &waiting_tasks, wait_list) {
        print_task(task);
    }

    return 0;
}

4. 性能分析:为何 Linux 链表如此高效?

4.1 时间复杂度分析

操作 时间复杂度 说明
插入(头部/尾部) O(1) 仅修改4个指针
删除 O(1) 仅修改2个指针
查找 O(n) 需要遍历
判断空链表 O(1) 仅比较指针

4.2 缓存友好性分析

侵入式设计的优势

复制代码
传统链表(缓存不友好):
CPU Cache Line: ┌────────────────────────────┐
                │ Node* 指针                 │  ← 缓存 miss
                └────────────────────────────┘
                ┌────────────────────────────┐
                │ 实际数据                   │  ← 再次缓存 miss
                └────────────────────────────┘

Linux链表(缓存友好):
CPU Cache Line: ┌────────────────────────────┐
                │ struct student            │
                │   id, name, age, list     │  ← 一次缓存加载
                └────────────────────────────┘

空间局部性:数据和链表指针连续存储在同一缓存行中,减少缓存 miss。

时间局部性:遍历链表时,相邻节点通常在内存中连续分配,预取机制可提前加载。


5. 常见错误与陷阱

5.1 忘记初始化链表节点

错误代码

c 复制代码
struct student *s = malloc(sizeof(struct student));
s->id = 1;
list_add(&s->list, &student_list);  // 未初始化!s->list.next/prev 是随机值

正确代码

c 复制代码
struct student *s = malloc(sizeof(struct student));
s->id = 1;
INIT_LIST_HEAD(&s->list);  // 必须先初始化!
list_add(&s->list, &student_list);

5.2 在遍历中直接删除节点

错误代码

c 复制代码
list_for_each(pos, &student_list) {
    struct student *stu = list_entry(pos, struct student, list);
    if (stu->id == 2) {
        list_del(pos);  // 删除后 pos 变成悬空指针!
        free(stu);
    }
}

正确代码:使用安全遍历宏

c 复制代码
struct list_head *pos, *n;
list_for_each_safe(pos, n, &student_list) {
    struct student *stu = list_entry(pos, struct student, list);
    if (stu->id == 2) {
        list_del(pos);
        free(stu);
    }
}

5.3 重复删除节点

错误代码

c 复制代码
list_del(&s->list);
// ... 其他代码 ...
list_del(&s->list);  // s->list.next/prev 已被设为 NULL,会崩溃!

建议:删除后立即将指针置 NULL 或使用标志位标记。


6. 单元测试建议

为链表操作编写单元测试是工程化开发的良好实践:

c 复制代码
#include <assert.h>

void test_list_operations() {
    LIST_HEAD(test_list);
    
    // 测试空链表
    assert(list_empty(&test_list) == 1);
    
    // 创建测试节点
    struct student *s1 = malloc(sizeof(struct student));
    s1->id = 1;
    INIT_LIST_HEAD(&s1->list);
    
    // 测试插入
    list_add(&s1->list, &test_list);
    assert(list_empty(&test_list) == 0);
    
    // 测试遍历
    struct student *stu;
    list_for_each_entry(stu, &test_list, list) {
        assert(stu->id == 1);
    }
    
    // 测试删除
    list_del(&s1->list);
    free(s1);
    assert(list_empty(&test_list) == 1);
    
    printf("All tests passed!\n");
}

7. 设计优势对比

特性 Linux 内核链表 传统链表 优势说明
类型通用性 一套宏支持所有类型 每种类型需单独实现 代码复用性高
内存开销 零额外开销 每个节点额外分配 节省内存
多链表支持 一个结构体可嵌入多个节点 难以实现 灵活性强
缓存友好 数据和指针连续存储 数据和指针分离 性能更好
代码简洁 宏展开为内联代码 函数调用开销 执行效率高
可维护性 集中维护一套宏 分散维护多套实现 易于维护

8. 总结与展望

8.1 核心知识点回顾

  1. 侵入式设计 :将 list_head 嵌入到用户结构体中,实现类型无关
  2. list_entry 宏:通过偏移量计算从链表节点获取结构体指针
  3. O(1) 复杂度:插入和删除操作只需修改指针
  4. 缓存友好:数据和指针连续存储,提高缓存命中率

8.2 进阶思考

  1. 如何实现反向遍历宏 list_for_each_entry_reverse
  2. 如果需要在遍历过程中同时修改链表结构,应该注意什么?
  3. 如何实现链表的合并、拆分操作?

8.3 扩展阅读

  • 内核源码include/linux/list.h - Linux 内核链表实现
  • 经典书籍:《Linux 内核设计与实现》第三章 - 进程管理中的链表应用
  • 进阶数据结构 :Linux 内核中的哈希表 (hlist)、红黑树 (rbtree)

附录:宏/函数速查表(按功能分类)

初始化

宏/函数 语法
LIST_HEAD(name) 声明并初始化链表头
INIT_LIST_HEAD(list) 动态初始化链表节点

插入

宏/函数 语法
list_add(new, head) 头部插入
list_add_tail(new, head) 尾部插入

删除

宏/函数 语法
list_del(entry) 删除节点

遍历

宏/函数 语法
list_for_each(pos, head) 遍历节点指针
list_for_each_safe(pos, n, head) 安全遍历
list_for_each_entry(pos, head, member) 遍历结构体

条目访问

宏/函数 语法
list_entry(ptr, type, member) 获取结构体指针
list_first_entry(ptr, type, member) 获取第一个元素
list_last_entry(ptr, type, member) 获取最后一个元素
list_next_entry(pos, member) 获取下一个元素

相关推荐
utf8mb4安全女神1 小时前
shell脚本
linux·运维·服务器
花果山~~程序猿1 小时前
ubuntu20.4下载python3.12
linux
daad7772 小时前
sitl_5760_io记录
linux·运维·服务器
XIAOHEZIcode2 小时前
进程、会话与终端——一次真实的 Linux Session 解剖
linux·后端·命令行
好好风格2 小时前
Scrapling:现代 Web 抓取,正在从“写选择器”走向“自适应”
linux·后端
用户2367829801682 小时前
Linux chown 命令详解:从 inode 到实战
linux
不做无法实现的梦~2 小时前
Ubuntu 22.04 下使用 CMSIS-DAP 编译和烧录 STM32
linux·stm32·ubuntu
Junsir大斗师2 小时前
rocky9.7搭建grafana+loki+prometheus+alloy+node_exporter运维监控平台
linux·运维·grafana·prometheus
小此方2 小时前
Re:Mysql数据库基础篇(一):CentOS/Linux 环境下的完整安装/运行/登录Mysql流程与首次登录异常处理
linux·数据库·mysql