数据结构之Linux Kernel双向链表(一)
2013-12-26 13:34
169 查看
Linux Kernel双向链表
链表是Linux Kernel中最简单的数据结构。
常规链表 的使用 是将数据结构塞入链表中,Linux Kernel中 链表的使用比较独特 ,是将链表节点塞入数据结构中。通过遍历链表 再通过相对位移 找到数据结构。
Linux Kernel中,链表代码在头文件<linux/list.h>中申明。
在使用的时候 嵌入到自己的数据结构中。
那么如何通过遍历list链表找到真正可以用的数据结构(a和b)呢?
内核中通过container_of()宏实现
@type为数据结构 结构体类型。
@member是type结构体中的成员。
offsetof宏是求得成员member相对于type结构体的首地址的偏移量
@ptr 是指向大结构体中member成员的指针
@type 是大结构体的类型
@member 是大结构体中的某个成员的名字
container_of宏 是根据大结构体中的某个成员的地址,求得大结构体的首地址
这样Linux Kernel 提供了链表各种最基本的操作方法,而不需要知道list_head所嵌入对象的数据结构。所以不同的数据结构都可以使用Linux 内核链表。
Linux 内核链表常用操作有:
1、初始化链表
5、遍历链表
6、遍历大结构体
参考:Linux内核设计与实现第三版
链表是Linux Kernel中最简单的数据结构。
常规链表 的使用 是将数据结构塞入链表中,Linux Kernel中 链表的使用比较独特 ,是将链表节点塞入数据结构中。通过遍历链表 再通过相对位移 找到数据结构。
Linux Kernel中,链表代码在头文件<linux/list.h>中申明。
struct list_head { struct list_head *prev; struct list_head *next; };next指针指向下一个链表节点,prev指针指向前一个节点。
在使用的时候 嵌入到自己的数据结构中。
struct test_node { int a; char b; struct list_head list; /* 链表 */ };上例中 test_node中的list.next指向下一个元素,list.prev指向前一个元素。这样 所有的元素 都通过list链表连起来了。
那么如何通过遍历list链表找到真正可以用的数据结构(a和b)呢?
内核中通过container_of()宏实现
#define offsetof(type , member) ( (size_t)(&((type*)0)->member) )
@type为数据结构 结构体类型。
@member是type结构体中的成员。
offsetof宏是求得成员member相对于type结构体的首地址的偏移量
#define container_of(ptr, type, member) ( (type*)((size_t)ptr - offsetof(type, member)) )
@ptr 是指向大结构体中member成员的指针
@type 是大结构体的类型
@member 是大结构体中的某个成员的名字
container_of宏 是根据大结构体中的某个成员的地址,求得大结构体的首地址
这样Linux Kernel 提供了链表各种最基本的操作方法,而不需要知道list_head所嵌入对象的数据结构。所以不同的数据结构都可以使用Linux 内核链表。
Linux 内核链表常用操作有:
1、初始化链表
static void INIT_LIST_HEAD(struct list_head *list) { list->prev = list; list->next = list; }2、插入链表
static void __list_add(struct list_head *list, struct list_head *prev_node, struct list_head *next_node) { list->prev = prev_node; list->next = next_node; prev_node->next = list; next_node->prev = list; }头插
static void list_add(struct list_head *list, struct list_head *head) { __list_add(list, head, head->next); }尾插
static void list_add_tail(struct list_head *list , struct list_head *head) { __list_add(list, head->prev, head); }3、删除节点
static void list_del(struct list_head *list) { list->prev->next = list->next; list->next->prev = list->prev; INIT_LIST_HEAD(list);//指向自己 }4、判断是否为空
static int list_is_empty(struct list_head *list) { return list->next == list; }
5、遍历链表
#define list_for_each(cur, head) \ for(cur = (head)->next; (cur) != (head); cur = (cur)->next)安全遍历
#define list_for_each_safe(cur, tmp, head) for(cur = (head)->next, tmp = (cur)->next; (cur) != (head); cur = (tmp), tmp = (tmp)->next )
6、遍历大结构体
#define list_for_each_entry(ptr, head, member) for( ptr = container_of((head)->next, typeof(*(ptr)), member); &((ptr)->member) != (head); \ ptr = container_of((ptr)->member.next, typeof(*(ptr)), member) )
参考:Linux内核设计与实现第三版
相关文章推荐
- [C/C++]反转链表
- Linux内核链表实现过程
- 找出链表倒数第n个节点元素的二个方法
- Java数据结构之简单链表的定义与实现方法示例
- STL list链表的用法详细解析
- 编码实现从无序链表中移除重复项(C和JAVA实例)
- 结构之美:单链表的初始化、创建与遍历
- 结构之美:单链表的头结点与头指针
- 带头结点与不带头结点的单链表初始化
- 带头结点的单链表的12个基本操作
- 单链表的基础知识问与答
- 结构之美:使用头插法创建单链表
- 结构之美:单链表的销毁删除
- 怎样才算是掌握单链表呢?
- 结构之美:查找单链表指定位置结点的数据
- 结构之美:删除单链表指定位置的数据
- 结构之美:单链表逆序
- 结构之美:判断单链表中是否有环
- 结构之美:获取单链表倒数第N个结点值
- 腾讯面试题:快速找到未知长度单链表的中间节点