# MircoUiFw **Repository Path**: lee8871/mirco-ui-fw ## Basic Information - **Project Name**: MircoUiFw - **Description**: 这是一个刚刚建立的嵌入式UI框架。所谓框架,是因为希望这个程序提供UI的顶层架构,而后续的显示效果,可以随用随添。 最后希望这个能做的足够简单易用吧。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-23 - **Last Updated**: 2025-08-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # CSimpleList - 通用链表库 CSimpleList 是一个轻量级、灵活的通用链表实现,专为嵌入式系统和资源受限环境设计。它支持多结构体、多指针场景,允许一个节点同时属于多个不同的链表。 ## 特性 - **通用性** - 可用于任意结构体类型的链表操作 - **多指针支持** - 单个节点可以同时属于多个链表 - **内存效率** - 无需额外的链表容器,直接使用节点内的指针字段 - **C/C++兼容** - 提供C语言接口,可在C和C++项目中使用 - **回调机制** - 支持自定义节点遍历和条件删除操作 - **零依赖** - 不依赖标准库或其他外部库 ## 设计原理 CSimpleList 使用指针偏移技术来实现通用链表操作,允许在不同的结构体中使用不同位置的指针字段。这种设计具有以下优势: 1. 没有固定的节点结构要求,任何带有指针字段的结构都可以作为节点 2. 一个节点可以同时属于多个链表,只要结构中有多个指针字段 3. 无需为节点类型编写特定的链表操作函数,通用函数可处理所有类型 ## API参考 ### 基本操作 ```c // 在链表尾部添加节点 void Linklist_append(tPtr* head, char next_diff, tPtr new_node); // 在链表头部插入节点 void Linklist_prepend(tPtr* head, char next_diff, tPtr new_node); // 移除并返回链表第一个节点 tPtr Linklist_removeFirst(tPtr* head, char next_diff); // 移除并返回链表最后一个节点 tPtr Linklist_removeLast(tPtr* head, char next_diff); ``` ### 高级操作 ```c // 遍历链表并对每个节点执行回调函数 int Linklist_foreach(tPtr* head, char next_diff, int (*callback)(tPtr node, void* tag), void* tag); // 遍历链表并删除符合条件的节点 int Linklist_removeIf(tPtr* head, char next_diff, int (*predicate)(tPtr node, void* tag), void* tag); ``` ### 回调控制值 ```c enum sIterateCtrl { eIterateCtrl_Continue = 0, // 继续遍历 eIterateCtrl_Stop = 1, // 停止遍历 eIterateCtrl_Remove = 2, // 删除当前节点并继续遍历 eIterateCtrl_RemoveStop = 3 // 删除当前节点并停止遍历 }; ``` ## 使用示例 ### 基本链表操作 ```c // 定义自定义节点结构 typedef struct MyNode { int value; struct MyNode* next; } MyNode; // 创建节点 MyNode* createNode(int value) { MyNode* node = malloc(sizeof(MyNode)); node->value = value; node->next = NULL; return node; } // 计算next指针在结构体中的偏移量 char next_diff = (char*)&((MyNode*)0)->next - (char*)0; // 创建链表并添加节点 MyNode* head = NULL; Linklist_append((tPtr*)&head, next_diff, createNode(10)); Linklist_append((tPtr*)&head, next_diff, createNode(20)); Linklist_prepend((tPtr*)&head, next_diff, createNode(5)); // 删除节点 MyNode* first = (MyNode*)Linklist_removeFirst((tPtr*)&head, next_diff); MyNode* last = (MyNode*)Linklist_removeLast((tPtr*)&head, next_diff); ``` ### 链表遍历与回调 ```c // 打印节点回调函数 int printNode(tPtr node, void* tag) { MyNode* my_node = (MyNode*)node; printf("节点值: %d\n", my_node->value); return 0; // 继续遍历 } // 查找特定值回调函数 int findValue(tPtr node, void* tag) { MyNode* my_node = (MyNode*)node; int target = *(int*)tag; if(my_node->value == target) { return 1; // 找到目标,停止遍历 } return 0; // 继续遍历 } // 遍历链表 Linklist_foreach((tPtr*)&head, next_diff, printNode, NULL); // 查找值为20的节点 int target = 20; int index = Linklist_foreach((tPtr*)&head, next_diff, findValue, &target); ``` ### 条件删除节点 ```c // 删除偶数值节点的回调函数 int removeEvenNodes(tPtr node, void* tag) { MyNode* my_node = (MyNode*)node; if(my_node->value % 2 == 0) { return 2; // 删除节点并继续遍历 } return 0; // 继续遍历 } // 删除所有偶数值节点 int removed_count = Linklist_removeIf((tPtr*)&head, next_diff, removeEvenNodes, NULL); ``` ### 多链表示例 ```c // 定义带有多个指针的节点结构 typedef struct MultiNode { int value; struct MultiNode* next_1; // 用于第一个链表 struct MultiNode* next_2; // 用于第二个链表 } MultiNode; // 计算两个next指针的偏移量 char next_1_diff = (char*)&((MultiNode*)0)->next_1 - (char*)0; char next_2_diff = (char*)&((MultiNode*)0)->next_2 - (char*)0; // 创建两个不同的链表 MultiNode* list1 = NULL; MultiNode* list2 = NULL; // 创建节点 MultiNode* node = malloc(sizeof(MultiNode)); node->value = 100; node->next_1 = NULL; node->next_2 = NULL; // 节点同时添加到两个不同的链表 Linklist_append((tPtr*)&list1, next_1_diff, node); Linklist_append((tPtr*)&list2, next_2_diff, node); ``` ## 实现细节 CSimpleList 使用指针偏移技术来访问节点内的next指针: ```c #define NEXT(NODE) *((tPtr*)(next_diff + (char*)NODE)) ``` 这个宏定义通过计算指针字段在结构体中的偏移量来访问任意结构体中的next指针,实现了通用链表操作。 在 `removeIf` 函数中,使用了虚拟头节点技术来简化删除逻辑: ```c tPtr virtual_first_node = (tPtr)((char*)head - next_diff); ``` ## 注意事项 1. 在使用 `Linklist_removeFirst` 或 `Linklist_removeLast` 时,返回的节点内存需要由调用方负责释放 2. 在使用 `Linklist_removeIf` 时,被删除的节点不会自动释放,需要在回调函数或其他地方处理内存释放 3. 务必正确计算next指针在结构体中的偏移量,否则可能导致内存访问错误 4. 本库不检查循环链表,使用时需要避免形成环路 ## 测试 项目包含全面的测试套件(`CSimpleListTest.c`),验证了链表的各项功能: - 基本链表操作(增、删、边界场景) - 节点在多个链表中的行为 - 链表遍历与回调函数 - 条件删除功能 运行 `run_all_tests()` 函数以执行所有测试用例。 ## 许可 此代码使用MIT许可证,详情请参见LICENSE文件。