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编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。

全部评论

相关推荐

优化前端性能是一个广泛的领域,有很多方法可以提高网站或应用程序的加载速度和性能。以下是一些常见的优化技巧:https://www.nowcoder.com/issue/tutorial?zhuanlanId=Mg58Em&uuid=07d53be4cd034a4ab270d500feebcc8d压缩和合并文件:将CSS和JavaScript文件压缩和合并成一个文件可以减少网络请求的数量,从而加快页面加载速度。图片优化:通过压缩图片文件大小、使用适当的图像格式(如JPEG、PNG)以及懒加载技术来减少图片加载时间。缓存机制:使用浏览器缓存来存储静态资源,以减少重复下载。异步加载:将不必要的资源推迟加载,例如使用异步脚本或将JavaScript放置在页面底部。延迟加载:对于长页面或含有大量内容的页面,可以使用延迟加载技术,只在页面滚动到可见区域时加载内容。减少HTTP请求:减少网页中的资源数量,例如合并CSS和JavaScript文件、使用CSS Sprites技术等。响应式设计:为移动设备进行优化,使用响应式设计,确保网站在不同屏幕尺寸上都能良好显示和操作。使用CDN:使用内容分发网络(CDN)可以将静态资源分发到全球各个服务器上,加快资源加载速度。优化代码:通过减少DOM操作、避免不必要的重绘和重排等技术来优化JavaScript代码。使用性能分析工具:使用工具如Chrome开发者工具或PageSpeed Insights等来分析和识别潜在的性能瓶颈,并采取相应的优化措施。
校招求职吐槽
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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