linux内核链表在/usr/src/linux-headers-xxx/include/linux/list.h中可以看到,其中xxx为内核版本号。我们可以采用内核链表的方式实现我们自己的数据结构。
内核链表节点定义的结构体中只包含了指针域,
struct list_head {
struct list_head *next, *prev;
};
那么数据放在哪里呢?实际上内核链表是通过两层结构体的方式实现的,大结构体里面包含数据域和一个小结构体,该小结构体也就是上面的节点,链表通过小结构体联系起来,然后访问数据时通过container_of宏从小结构体转向大结构体。
#define offset_of(type, member) \
((size_t)(&(((type *)0)->member)))
#define container_of(ptr, type, member) \
(type *)((size_t)(ptr) - offset_of(type, member))
然后内核链表的实现采用了内联函数提高效率,相对于普通双链表,内核链表多了一步大小结构体转换的过程,其他的都差不多。下面是简易的lish.h
#pragma once
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(head) \
struct list_head (head) = {&head, &head}
static inline void list_head_init(struct list_head *head)
{
head->next = head;
head->prev = head;
}
static inline void __list_add(struct list_head *new, struct list_head *Prev, struct list_head *Next)
{
new->next = Next;
new->prev = Prev;
Prev->next = new;
Next->prev = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void node_del(struct list_head *node)
{
node->next->prev = node->prev;
node->prev->next = node->next;
}
static inline void node_del_init(struct list_head *node)
{
node_del(node);
list_head_init(node);
}
#define list_for_each(cur, head) \
for ((cur) = (head)->next; (cur) != (head); (cur) = (cur)->next)
#define offset_of(type, member) \
((size_t)(&(((type *)0)->member)))
#define container_of(ptr, type, member) \
(type *)((size_t)(ptr) - offset_of(type, member))
#define list_for_each_reverse(cur, head) \
for (cur = (head)->prev; cur != (head); cur = (cur)->prev)
#define list_for_each_continue(cur, head) \
for (cur = (cur)->next; cur != (head); cur = (cur)->next)
#define list_for_each_from(cur, head) \
for ( ; cur != (head); cur = (cur)->next)
/*直接遍历大结构体(宿主结构)*/
#define list_for_each_entry(pos, head, member) \
for (pos = container_of((head)->next, typeof(*pos), member); &(pos)->member != head; \
pos = container_of((pos)->member.next, typeof(*pos), member))
简单的测试
#include <stdio.h>
#include "list.h"
struct data_info {
char *name;
int age;
struct list_head list;
};
int main(void)
{
LIST_HEAD_INIT(head);
struct data_info s[] = {
{"mary", 25},
{"candy", 18},
{"jack", 24},
};
int i = 0;
for (; i < sizeof(s) / sizeof(s[0]); i++) {
list_add(&s[i].list, &head);
}
struct list_head *cur = NULL;
struct data_info *pa = NULL;
list_for_each(cur, &head) {
pa = container_of(cur, struct data_info, list);
printf("%s %d\n", pa->name, pa->age);
}
return 0;
}