嵌入式C语言那点事(三)Linux中霸道的双向链表源码与应用
2012-05-19 15:29
399 查看
C语言作为面向过程的语言,想写出灵活的结构与封装需要很高技巧。
但由于C语言的高效,几乎所有操作系统和面向对象语言的最底层实现都使用了C语言。即,使用C完成面向对象的封装。
这次通过整理与仿写Linux的双向链表让我体会到了一些C语言封装的核心技巧。
这个双向链表的巧妙之处在于1)利用宏将“函数”入参扩展出了“结构类型”; 2)利用纯地址偏移获取结构体指针;
下面是具体实现:链表的实现由于是宏定义,都在libList.h中。
测试程序testList.c与testList.h。
libList.h
testList.h
这种双向链表的特点在于:在需要链表管理的结构中定义一个链表节点变量,然后所有的操作都是针对这个链表节点进行的。在需要获取该结构时使用list_entry即可。
testList.c
但由于C语言的高效,几乎所有操作系统和面向对象语言的最底层实现都使用了C语言。即,使用C完成面向对象的封装。
这次通过整理与仿写Linux的双向链表让我体会到了一些C语言封装的核心技巧。
这个双向链表的巧妙之处在于1)利用宏将“函数”入参扩展出了“结构类型”; 2)利用纯地址偏移获取结构体指针;
下面是具体实现:链表的实现由于是宏定义,都在libList.h中。
测试程序testList.c与testList.h。
libList.h
#ifndef _LIBLIST_H #define _LIBLIST_H #ifdef __cplusplus extern "C" { #endif /* 链表头节点定义 */ typedef struct tagstList_Head { struct tagstList_Head *next, *prev; }stList_Head; /* 初始化双向链表 */ #define list_init(head) do \ { \ (head)->next = (head)->prev = (head); \ } while(0) /* 在指定元素(where)之后插入新元素(item) */ #define list_add(item, towhere) do \ { \ (item)->next = (towhere)->next; \ (item)->prev = (towhere); \ (towhere)->next = (item); \ (item)->next->prev = (item); \ } while(0) /* 在指定元素(where)之前插入新元素(item) */ #define list_add_before(item, towhere) \ list_add(item,(towhere)->prev) /* 删除某个元素 */ #define list_remove(item) do \ { \ (item)->prev->next = (item)->next; \ (item)->next->prev = (item)->prev; \ } while(0) /* 正向遍历链表中所有元素 */ #define list_for_each_item(item, head)\ for ((item) = (head)->next; (item) != (head); (item) = (item)->next) /* 反向遍历链表中所有元素 */ #define list_for_each_item_rev(item, head) \ for ((item) = (head)->prev; (item) != (head); (item) = (item)->prev) /* 根据本节点(item)获取节点所在结构体(type)的地址 */ /* 节点item地址(member的地址) - 该链表元素member在结构体中的偏移 */ #define list_entry(item, type, member) \ ((type *)((char *)item - (char *)(&((type *)0)->member))) /* 判断链表是否为空 */ #define list_is_empty(head) \ ((head)->next == (head)) /* 获取指定位置上一元素 */ #define list_prev_item(item)\ ((head)->prev) #ifdef __cplusplus } #endif #endif
testList.h
#ifndef _TESTLIST_H #define _TESTLIST_H #ifdef __cplusplus extern "C" { #endif #include "libList.h" typedef struct tagInteger { int idx; stList_Head stListHead; }stInteger; extern void testlist(); #ifdef __cplusplus } #endif #endif
这种双向链表的特点在于:在需要链表管理的结构中定义一个链表节点变量,然后所有的操作都是针对这个链表节点进行的。在需要获取该结构时使用list_entry即可。
testList.c
#ifdef __cplusplus extern "C" { #endif #include <malloc.h> #include <stddef.h> #include "stdafx.h" #include "testList.h" void testlist() { int i = 0; stList_Head stListHead; stList_Head *pstListHead= NULL; stInteger *pstInteger = NULL; stList_Head *pstTmpList = NULL; /* 链表初始化 */ pstListHead = &stListHead; list_init(pstListHead); /* 生成节点并挂入链表 */ for(i = 0; i < 32; i++) { pstInteger = (stInteger *)malloc(sizeof(stInteger)); if (NULL == pstInteger) { printf("pstInteger malloc fail!"); return; } pstInteger->idx = 100 - i; /* 挂到头结点之前 */ list_add_before(&pstInteger->stListHead, pstListHead); /* 挂到头结点之后 */ //list_add(&pstInteger->stListHead, pstListHead); } /* 正向遍历链表中每一个元素并输出 */ list_for_each_item(pstTmpList, pstListHead) { if(NULL != pstTmpList) { pstInteger = list_entry(pstTmpList, stInteger, stListHead); printf("%d ",pstInteger->idx); } } return; } #ifdef __cplusplus { #endif
相关文章推荐
- Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)
- Linux内核2.6.14源码分析-双向循环链表代码分析
- [精华]]Linux内核2.6.14源码分析-双向循环链表代码分析(转)
- Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)
- Linux内核2.6.14源码分析-双向循环链表代码分析
- java 语言中链表和双向链表的实现!
- 成都国嵌-嵌入式linux必修实验手册完整版以及实验源码
- 嵌入式Linux系统设计--第七章:嵌入式Linux接口与应用开发
- 嵌入式Linux工控主板调试串口转换为应用串口的方法
- 详解Linux内核之双向循环链表
- 嵌入式linux开发uboot移植(二)——uboot工程源码目录分析
- 【嵌入式Linux学习七步曲之第七篇 Linux的高级应用编程】Linux下的多线程编程
- VMWare 在嵌入式Linux开发的应用
- Linux利用list_head结构实现双向链表
- 嵌入式C语言那点事(二)栈与队列的实现
- libxml2库在嵌入式linux中的应用
- 运维之系统服务篇------2.linux扩展应用 、 vim编辑技巧 、 发布网络YUM源 、 源码编译安装
- 从嵌入式linux到android应用开发
- 剑指offer系列源码-二叉搜索树与双向链表
- Linux中的双向循环链表