FreeRTOS源码解析(通用链表)

3.1通用链表和普通链表的对比

普通链表的数据域往往绑定某种固定类型(比如 intstruct Person 等)。

// 普通链表节点
typedef struct node
{
    int data;              // 存放的数据
    struct node* next;     // 指向下一个节点
} Node;

通用链表(Generic Linked List) 的特点是:

  • 不依赖具体数据类型
  • 节点的数据域一般使用 void * 指针 存储,这样可以指向任意类型的数据。
  • 用户在插入数据时,只需要传入一个指针即可,不管是 intfloat 还是自定义结构体,都能存储。

所以,通用链表其实是 通过抽象化设计,提升链表的复用性

// 通用链表节点
typedef struct gnode
{
    void* data;            // 存放任意数据指针
    struct gnode* next;    // 指向下一个节点
} GNode;

关键设计点

  • 数据存储形式: 使用 void* 指针来存放数据。这样一来,节点可以指向任何类型的数据。
  • 节点结构: 节点包含一个 void* data 和一个 next 指针(单链表),或 prev/next(双链表)。
  • 操作函数: 初始化:创建一个空链表头。插入:可以在链表头或尾部插入数据。删除:根据传入的条件(比如指针或比较函数)找到并删除节点。查找:通过比较函数查找某个数据。遍历:遍历链表时,调用一个用户自定义的“处理函数”,比如打印或释放。
  • 回调函数: 因为节点数据类型不确定,所以需要在遍历、查找、删除时传入回调函数,比如: int cmp(void* a, void* b) 用来比较两个数据是否相等void print(void* data) 用来打印数据
+-----------+      +-----------+      +-----------+
|  void*    | ---> |  void*    | ---> |  void*    |
|  next ----+      |  next ----+      |  next ----+
+-----------+      +-----------+      +-----------+
   | 数据指针           | 数据指针           | 数据指针
   v                  v                  v
 [int]              [string]          [struct obj]

通用链表框架:

/* 链表节点结构,将被嵌入到其他数据结构中 */
struct list_head {
    struct list_head *next;  // 指向下一个节点
    struct list_head *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;
}


初始化的对比:

全局/静态链表

struct list_head head = LIST_HEAD_INIT(head);

编译时初始化

局部链表

struct list_head head; INIT_LIST_HEAD(&head);

运行时初始化

动态链表

struct list_head *head = malloc(...); INIT_LIST_HEAD(head);

运行时初始化

静态初始化:

#define LIST_HEAD_INIT(name) { &(name), &(name) }

struct list_head my_list = LIST_HEAD_INIT(my_list);


struct list_head my_list = {
    .node = { .prev = &my_list, .next = &my_list }
};


动态初始化:

static inline void INIT_LIST_HEAD(struct list_head *list) {
    list->node.next = &list->node;
    list->node.prev = &list->node;
}


struct list_head my_list; // 没有初始化
INIT_LIST_HEAD(&my_list); // 在运行时初始化



3.2通用链表添加节点

__list_add 是一个 底层通用函数,它要求你明确指定要插入位置的 和 。

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

嵌入式面试八股文全集 文章被收录于专栏

这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。

全部评论

相关推荐

点赞 评论 收藏
分享
程序员小白条:四级很基础的要求,文理工很多都卡,迟早要过的,六级倒是还好,不过大多数人也都是过的,毕竟这种没难度的考试,含金量不大,就是提高一些门槛罢了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务