当前位置: 首页 > news >正文

c语言tips-结构体数组 VS 链表宏:`list_for_each_entry` 的优势与局限对比分析

0 . 写在开头

在嵌入式开发、操作系统内核或者一般的 C 语言项目中,我们经常需要管理一组结构体数据。对于初学者而言,使用结构体数组无疑是最直观的选择,数组简单、访问高效,代码逻辑也易于理解。然而,当项目变得更复杂、数据对象需要动态增删、或者不确定元素数量时,结构体数组开始显得捉襟见肘。这时,许多开发者会转向链表,尤其是在 Linux 内核中被广泛使用的宏式链表管理方式,比如 list_for_each_entry。本文将从实际使用角度出发,对比结构体数组与基于 list_for_each_entry内核链表遍历方式,分析它们在灵活性、性能、可维护性等方面的优劣,帮助你在实际工程中做出更合适的选择。

1. 示例代码对比

以下代码分别使用结构体数组和使用链表遍历的方式来管理一组结构体数据,分别做这种数据结构的建立和遍历

#include <stdio.h>
#include <stdlib.h>/* ------- 链表结构与宏 ------- */
struct list_head {struct list_head *next, *prev;
};#define INIT_LIST_HEAD(ptr) \do { (ptr)->next = (ptr); (ptr)->prev = (ptr); } while (0)#define list_entry(ptr, type, member) \((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))#define list_for_each_entry(pos, head, member)              \for (pos = list_entry((head)->next, typeof(*pos), member);    \&pos->member != (head);                            \pos = list_entry(pos->member.next, typeof(*pos), member))#define list_add_tail(new, head) do {           \(new)->prev = (head)->prev;                 \(new)->next = (head);                       \(head)->prev->next = (new);                 \(head)->prev = (new);                       \
} while (0)/* ------- 学生结构体 ------- */
struct student {int id;struct list_head list; // 仅用于链表方式
};#define STUDENT_COUNT 5int main() {printf("== 使用结构体数组管理 ==\n");struct student students[STUDENT_COUNT];for (int i = 0; i < STUDENT_COUNT; ++i) {students[i].id = i + 1;printf("Student id: %d\n", students[i].id);}printf("\n== 使用链表管理 ==\n");struct list_head student_list;INIT_LIST_HEAD(&student_list);for (int i = 0; i < STUDENT_COUNT; ++i) {struct student *s = malloc(sizeof(struct student));s->id = i + 1;list_add_tail(&s->list, &student_list);}struct student *s;list_for_each_entry(s, &student_list, list) {printf("Student id: %d\n", s->id);}return 0;
}

输出结果如下:
== 使用结构体数组管理 ==
Student id: 1
Student id: 2
Student id: 3
Student id: 4
Student id: 5

== 使用链表管理 ==
Student id: 1
Student id: 2
Student id: 3
Student id: 4
Student id: 5

我们将代码放到pythontutor运行,可以很直观的看到这两张数据结构的区别,并总结一下这两种方式的优缺点

在这里插入图片描述

场景 / 特性结构体数组list_for_each_entry 链表
元素数量固定✅ 适合❌ 不适合
动态增删元素❌ 不适合✅ 非常适合
代码简洁性✅ 简单直观❌ 依赖宏和嵌套结构
操作效率(遍历)✅ 更快(顺序内存)❌ 指针跳跃开销大
内存管理复杂度✅ 静态分配或一块申请❌ 手动分配和释放
实时系统 / 嵌入式开发✅ 适合小系统✅ 广泛用于内核、嵌入式协议栈
http://www.xdnf.cn/news/947827.html

相关文章:

  • 《解锁JNA与CUDA内核密码,定制专属AI算子》
  • SDC命令详解:使用set_wire_load_model命令进行约束
  • 二分查找算法
  • WEB3全栈开发——面试专业技能点P6后端框架 / 微服务设计
  • 可下载旧版app屏蔽更新的app市场
  • 判断是否是润年
  • 【投稿优惠】2025年航天技术 、雷达信号与无人机应用国际会议 (ATRA 2025)
  • Fail2ban开源入侵检测,保护SSH,NGINX等
  • 2025盘古石杯决赛【手机取证】
  • 手机平板能效生态设计指令EU 2023/1670标准解读
  • SQL Server 触发器调用存储过程实现发送 HTTP 请求
  • AI 导游:开启智能旅游新时代
  • CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
  • 基于matlab策略迭代和值迭代法的动态规划
  • 基于 CNN-SHAP 分析卷积神经网络的多分类预测【MATLAB】
  • Matlab | 基于matlab的图像去噪的原理及实现
  • 【MATLAB第119期】基于MATLAB的KRR多输入多输出全局敏感性分析模型运用(无目标函数,考虑代理模型)
  • (原创改进)73-CEEMDAN-VMD-SSA-LSSVM功率/风速时间序列预测!
  • Linux 文本比较与处理工具:comm、uniq、diff、patch、sort 全解析
  • Selenium4+Pytest自动化测试框架
  • 基于 Three.js 的 3D 模型快照生成方案
  • FOUPK3云服务平台主体
  • Kafka主题运维全指南:从基础配置到故障处理
  • 消息队列生产问题解决方案全攻略
  • 【C#】多级缓存与多核CPU
  • (12)-Fiddler抓包-Fiddler设置IOS手机抓包
  • Mysql8 忘记密码重置,以及问题解决
  • 数据可视化交互
  • 计算机网络自定向下:第二章复习
  • GPIO(通用输入输出)与LPUART(低功耗通用异步收发传输器)简述