list_head是Linux内核中使用最广泛的双向链表,每个节点都可以为任意类型,可以作为栈或队列使用,没有读过Linux内核的同学应该是没见过如此有创意的链表。
今天对linux内核中的list_head稍作修改,以便民用,不再是军用专属。
申明:本来很久没写代码了,没装任何IDE环境,所涉及到的代码不保证正确。今天只是蛋疼
直接上代码:
list_head.h
/***************************************************************************************************
*
* Linux的list_head链表民用改造
*
****************************************************************************************************
*
* 文 件:list_head.h
*
* 功能描述:
* 1. 大多数情况C码农们可能对不同数据类型需要创建不同类型的链表,使得代码量增加及运行时内存
* 的消耗增加。
* 2. Linux内核中有一个叫list_head的双向链表,各种总线驱动都使用list_head进行driver与device
* 之间的匹配,然后加载相应的驱动
* 3. 由于list_head可以挂任意类型的节点,因此每个节点对应的结构体中必须包含一个list_head类型
* 的成员,无其他要求。
*
* 创建日期:2016.12.29
* 作 者:oneonce
* 版 本:v1.00.000
*
***************************************************************************************************/
#ifndef __LIST_HEAD_H__
#define __LIST_HEAD_H__
#ifdef c__plusplus
extern "c"{
#endif
/***************************************************************************************************
使用方法:
struct test_node
{
int value;
list_head_t h;// 需要添加到list_head_t类型的列表节点结构体必须包含一个list_head_t成员
};
void test()
{
list_head_t my_list;
list_head_t *entry = NULL;
test_node a, b, c;
list_head_init(&my_list);
a.value = 1;
b.value = 2;
c.value = 3;
#if 0 // 压栈操作(列表作为栈使用)
list_push_stack(&a.h, &my_list);// a压栈
list_push_stack(&b.h, &my_list);// b压栈
list_push_stack(&c.h, &my_list);// c压栈
#else // 入列操作(列表作为队列使用)
list_enqueue(&a.h, &my_list);// a入列
list_enqueue(&b.h, &my_list);// b入列
list_enqueue(&c.h, &my_list);// c入列
#endif
int size = list_size(&my_list);// 列表大小
list_for_each(entry, &my_list)
{
test_node *node = list_entry(entry, struct test_node, h);
printf("node value: %d\n", node->value);
}
#if 0 // 出栈操作(列表作为栈使用)
entry = list_pop_stack(&a.h, &my_list);// a出栈
//entry = list_pop_stack(&b.h, &my_list);// b出栈
//entry = list_pop_stack(&c.h, &my_list);// c出栈
#else // 出列操作(列表作为队列使用)
entry = list_dequeue(&a.h, &my_list);// a出列
entry = list_dequeue(&b.h, &my_list);// b出列
entry = list_dequeue(&c.h, &my_list);// c出列
#endif
test_node *node = list_entry(entry, struct test_node, h);// 很关键。也是list_head最巧妙的地方,根据指向结构体中list_head成员的指针得到指向结构体的指针(自定义的结构体)
printf("出栈/出列node value: %d\n", node->value);
list_revese(&my_list);// 列表倒置
}
***************************************************************************************************/
#define offsetof(TYPE, MEMBER) (((size_t)&(TYPE *)0)->MEMBER)// 得到结构体成员在结构体中的偏移量
#define container_of(ptr, type, member) ((type *)((char *)ptr - offsetof(type, member)))// 得到指向结构体指针的首地址
#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)// for循环
#define list_for_each_r(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev)// 反向for循环
#define list_entry(ptr, type, member) (NULL == ptr)? NULL : container_of(ptr, type, member)// 根据‘指向结构体list_head_t成员指针’和‘结构体类型’以及结构体中‘list_head_t成员名’得到结构体首地址
typedef struct list_head
{
struct list_head *prev;
struct list_head *next;
} list_head_t, *plist_head_t;
typedef enum list_type
{
TYPE_UNKNOWN = -1,// 未知类型
TYPE_STACK,// 栈类型的列表
TYPE_QUEUE,// 队列类型的列表
} list_type_t;
int list_head_init(list_head_t *head);// 初始化表头,使用列表前必须初始化表头
int list_push_stack(list_head_t *entry, list_head_t *head);// 作为栈使用,把entry压入到以head为表头的列表中
list_head_t *list_pop_stack(list_head_t *head);// 作为栈使用,把以head为表头的列表中的栈顶节点出栈
int list_enqueue(list_head_t *entry, list_head_t *head);// 作为队列使用,把entry入列到以head为表头的列表中
list_head_t *list_dequeue(list_head_t *head);// 作为队列使用,把以head为表头的列表中队列头的节点出列
int list_insert_before(list_head_t *entry, list_head_t *ref, list_type_t type);// 在ref节点的前面插入entry节点
int list_insert_after(list_head_t *entry, list_head_t *ref, list_type_t type);// 在ref节点的后面插入entry节点
int list_insert(list_head_t *entry, list_head_t *prev, list_head_t *next);// 在prev和next节点之间插入entry节点
list_head_t *list_delete_entry(list_head_t *entry, list_head_t *head);// 从以head为表头的列表中删除entry节点,仅仅断开节点,返回断开节点后调用者释放内存
int list_is_empty(const list_head_t *head);// 以head为表头的列表是否为空
int list_size(const list_head_t *head);// 获取以head为表头的列表的大小
list_splice_to_head(list_head_t *_new, list_head_t *head);// 把新的列表_new合并到以head为表头的列表的头部
list_splice_to_tail(list_head_t *_new, list_head_t *head);// 把新的列表_new合并到以head为表头的列表的尾部
int list_replace(list_head_t *_new, list_head_t *old);// 把列表中old节点替换为新的_new节点
int list_revese(list_head_t *head);// 把以head为表头的列表中的所有节点前后顺序倒置,倒置后仍然以head为表头
#ifdef c__plusplus
}
#endif
#endif
list_head.c
/***************************************************************************************************
*
* Linux的list_head链表民用改造
*
****************************************************************************************************
*
* 文 件:list_head.c
*
* 功能描述:
* 1. 大多数情况C码农们可能对不同数据类型需要创建不同类型的链表,使得代码量增加及运行时内存
* 的消耗增加。
* 2. Linux内核中有一个叫list_head的双向链表,各种总线驱动都使用list_head进行driver与device
* 之间的匹配,然后加载相应的驱动
* 3. 由于list_head可以挂任意类型的节点,因此每个节点对应的结构体中必须包含一个list_head类型
* 的成员,无其他要求。
*
* 创建日期:2016.12.29
* 作 者:oneonce
* 版 本:v1.00.000
*
***************************************************************************************************/
#include <stdio.h>
#include "list_head.h"
#define LIST_POINT1 ((void *)0x00100100)
#define LIST_POINT2 ((void *)0x00200200)
typedef enum splice_mode
{
SPLICE_UNKNOWN = -1,
SPLICE_HEAD, // 合并列表时把新的列表合并都原有列表的表头
SPLICE_TAIL, // 合并列表时把新的列表合并都原有列表的表尾
} splice_mode_t;
static void __list_add(list_head_t *entry, list_head_t *prev, list_head_t *next);
static void __list_del(list_head_t *entry, list_head_t *prev, list_head_t *next);
static int __list_splice(list_head_t *list, list_head_t *head, splice_mode_t mode);
/***************************************************************************************************
* 函数名:int list_head_init(list_head_t *head)
* 功能描述:初始化表头,使用列表前必须初始化表头
* 输入参数:
* head :列表表头
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_head_init(list_head_t *head)
{
if (NULL == head)
{
return -1;
}
head->prev = head;
head->next = head;
return 0;
}
/***************************************************************************************************
* 函数名:int list_push_stack(list_head_t *entry, list_head_t *head)
* 功能描述:作为栈使用,把entry压入到以head为表头的列表中
* 输入参数:
* entry :待压栈节点
* head : 以head为表头的列表
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_push_stack(list_head_t *entry, list_head_t *head)
{
if (NULL == entry || NULL == head)
{
return -1;
}
__list_add(entry, head, head->next);
return 0;
}
/***************************************************************************************************
* 函数名:list_head_t *list_pop_stack(list_head_t *head)
* 功能描述:作为栈使用,把以head为表头的列表中的栈顶节点出栈
* 输入参数:
* head : 以head为表头的列表
* 输出参数:
* 无
* 返回值:
* 非NULL :成功
* NULL :失败
***************************************************************************************************/
inline list_head_t *list_pop_stack(list_head_t *head)
{
if (list_is_empty(head))
{
return NULL;
}
list_head_t *entry = head->next;
if (head != entry)
{
//list_head_t *next = entry->next;
//head->next = next;
//next->prev = head;
__list_del(entry, entry->prev, entry->next);
return entry;
}
return NULL;
}
/***************************************************************************************************
* 函数名:int list_enqueue(list_head_t *entry, list_head_t *head)
* 功能描述:作为队列使用,把entry入列到以head为表头的列表中
* 输入参数:
* entry :待入列节点
* head : 以head为表头的列表
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_enqueue(list_head_t *entry, list_head_t *head)
{
if (NULL == entry || NULL == head)
{
return -1;
}
__list_add(entry, head->prev, head);
return 0;
}
/***************************************************************************************************
* 函数名:list_head_t *list_dequeue(list_head_t *head)
* 功能描述:作为队列使用,把以head为表头的列表中队列头的节点出列
* 输入参数:
* head : 以head为表头的列表
* 输出参数:
* 无
* 返回值:
* 非NULL :成功
* NULL :失败
***************************************************************************************************/
inline list_head_t *list_dequeue(list_head_t *head)
{
return list_pop_stack(head);
}
inline void __list_add(list_head_t *entry, list_head_t *prev, list_head_t *next)
{
next->prev = entry;
entry->next = next;
entry->prev = prev;
prev->next = entry;
}
/***************************************************************************************************
* 函数名:int list_insert_before(list_head_t *entry, list_head_t *ref, list_type_t type)
* 功能描述:在ref节点的前面插入entry节点
* 输入参数:
* entry : 待插入节点
* ref : 插入点的参考节点
* type : 是否以栈还是队列方式进行操作
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_insert_before(list_head_t *entry, list_head_t *ref, list_type_t type)
{
if (NULL == entry || NULL == ref || TYPE_UNKNOWN == type)
{
return -1;
}
if (ref->prev == ref->next && ref == ref->prev)// 空列表
{
return -1;
}
if (TYPE_STACK == type)// 栈
{
__list_add(entry, ref, ref->next);
}
else if (TYPE_QUEUE == type)// 队列
{
__list_add(entry, ref->prev, ref);
}
return 0;
}
/***************************************************************************************************
* 函数名:int list_insert_after(list_head_t *entry, list_head_t *ref, list_type_t type)
* 功能描述:在ref节点的后面插入entry节点
* 输入参数:
* entry : 待插入节点
* ref : 插入点的参考节点
* type : 是否以栈还是队列方式进行操作
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_insert_after(list_head_t *entry, list_head_t *ref, list_type_t type)
{
if (NULL == entry || NULL == ref || TYPE_UNKNOWN == type)
{
return -1;
}
if (ref->prev == ref->next && ref == ref->prev)// 空列表
{
return -1;
}
if (TYPE_STACK == type)// 栈
{
__list_add(entry, ref->prev, ref);
}
else if (TYPE_QUEUE == type)// 队列
{
__list_add(entry, ref, ref->next);
}
return 0;
}
/***************************************************************************************************
* 函数名:int list_insert(list_head_t *entry, list_head_t *prev, list_head_t *next)
* 功能描述:在prev和next节点之间插入entry节点
* 输入参数:
* entry : 待插入节点
* prev : entry前节点
* next : entry后节点
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_insert(list_head_t *entry, list_head_t *prev, list_head_t *next)
{
if (NULL == entry || NULL == prev || NULL == next)
{
return -1;
}
if ((prev == next) || // 空列表
(prev->prev == prev->next && prev->prev == next))// 列表只有1个节点
{
return -1;// 无节点或1个节点没法插入,返回失败
}
if (prev->next == next)
{
__list_add(entry, prev, next);
}
else if (prev->prev == next)// 调用者把插入点前后传错了
{
__list_add(entry, next, prev);
}
else // 前后节点不相邻
{
return -1;
}
return 0;
}
/***************************************************************************************************
* 函数名:list_head_t *list_delete_entry(list_head_t *entry, list_head_t *head)
* 功能描述:从以head为表头的列表中删除entry节点,仅仅断开节点,返回断开节点后调用者释放内存
* 输入参数:
* entry : 待插入节点
* head : 列表表头
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline list_head_t *list_delete_entry(list_head_t *entry, list_head_t *head)
{
if (list_is_empty(head) || NULL == entry || head == entry)
{
return NULL;
}
__list_del(entry, entry->prev, entry->next);
return entry;
}
inline void __list_del(list_head_t *entry, list_head_t *prev, list_head_t *next)
{
next->prev = prev;
prev->next = next;
#if 0// 编译段错误(内核中)?
entry->prev = LIST_POINT1;
entry->next = LIST_POINT2;
#else
entry->prev = NULL;
entry->next = NULL;
#endif
}
/***************************************************************************************************
* 函数名:int list_is_empty(const list_head_t *head)
* 功能描述:以head为表头的列表是否为空
* 输入参数:
* head : 列表表头
* 输出参数:
* 无
* 返回值:
* 1 :空
* 0 :非空
***************************************************************************************************/
inline int list_is_empty(const list_head_t *head)
{
if (NULL == head)
{
return 1;
}
return head->next == head;
}
/***************************************************************************************************
* 函数名:int list_size(const list_head_t *head)
* 功能描述:获取以head为表头的列表的大小
* 输入参数:
* head : 列表表头
* 输出参数:
* 无
* 返回值:
* >0 :非空
* 0 :空
***************************************************************************************************/
inline int list_size(const list_head_t *head)
{
int size = 0;
list_head_t *entry = NULL;
if (NULL == head)
{
return 0;
}
list_for_each(entry, head)
{
size++;
}
return size;
}
/***************************************************************************************************
* 函数名:int list_splice_to_head(list_head_t *_new, list_head_t *head)
* 功能描述:把新的列表_new合并到以head为表头的列表的头部
* 输入参数:
* _new : 待合并列表
* head : 原有列表
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_splice_to_head(list_head_t *_new, list_head_t *head)
{
return __list_splice(_new, head, SPLICE_HEAD);
}
/***************************************************************************************************
* 函数名:int list_splice_to_tail(list_head_t *_new, list_head_t *head)
* 功能描述:把新的列表_new合并到以head为表头的列表的尾部
* 输入参数:
* _new : 待合并列表
* head : 原有列表
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_splice_to_tail(list_head_t *_new, list_head_t *head)
{
return __list_splice(_new, head, SPLICE_TAIL);
}
inline int __list_splice(list_head_t *list, list_head_t *head, splice_mode_t mode)
{
list_head_t *first = NULL;
list_head_t *last = NULL;
if (NULL == list || list_is_empty(list) || list_is_empty(head) || SPLICE_UNKNOWN == mode)
{
return -1;
}
first = list->next;
last = list->prev;
if (SPLICE_HEAD == mode)
{
list_head_t *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
else if (SPLICE_TAIL == mode)
{
list_head_t *at = head->prev;
first->prev = at;
at->next = first;
last->next = head;
head->prev = last;
}
return 0;
}
/***************************************************************************************************
* 函数名:int list_replace(list_head_t *_new, list_head_t *old)
* 功能描述:把列表中old节点替换为新的_new节点
* 输入参数:
* _new : 待替换节点
* old : 被替换节点
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_replace(list_head_t *_new, list_head_t *old)
{
if (NULL == _new || NULL == old)
{
return -1;
}
_new->next = old->next;
_new->next->prev = _new;
_new->prev = old->prev;
_new->prev->next = _new;
}
/***************************************************************************************************
* 函数名:int list_revese(list_head_t *head)
* 功能描述:把以head为表头的列表中的所有节点前后顺序倒置,倒置后仍然以head为表头
* 输入参数:
* head : 表头
* 输出参数:
* 无
* 返回值:
* 0 :成功
* -1 :失败
***************************************************************************************************/
inline int list_revese(list_head_t *head)
{
list_head_t *first = NULL;
list_head_t *entry = NULL;
if (NULL == head)
{
return -1;
}
if (list_is_empty(head)
{
return -1;
}
first = head->next;
while (head != first->next)
{
entry = first->next;
first->next = entry->next;
entry->next->prev = first;
head->next->prev = entry;
entry->next = head->next;
head->next = entry;
entry->prev = head;
}
return 0;
}