内核双向循环链表

普通的双向循环链表,一般将前向指针 p r e v prev prev以及后向指针 n e x t next next内嵌到特定的数据结构中。
再根据这种特定的结构编写插入,删除等函数。

node1
node2
node3
struct myOrdinaryType {
    int data;
    struct myOrdinaryType *prev, *next;
};

这里介绍一种通用的双向循环链表,可以不依赖具体的数据类型。

struct list_entry_t {
    struct list_entry_t *prev, *next;
};
struct myType{
    int data;
    list_entry_t list_entry;
};
node3
node2
node1
data3
list_entry_t3
data2
list_entry_t2
data1
list_entry_t1

如图所示,将 l i s t _ e n t r y _ t list\_entry\_t list_entry_t类型作为自定义类型的一个成员,内嵌到结构体中。
注意箭头的指向,上图中指针指向的是整体,该图中指针指向的是成员。
注意 l i s t _ e n t r y _ t list\_entry\_t list_entry_t类型是通用的,不需要依赖特定的数据类型。

初始化操作,直接将节点的前向指针和后向指针指向自己。

static inline void list_init(list_entry_t* elm) {
    elm->prev = elm->next = elm;
}

下面是两个基础的插入,删除操作。

static inline void __list_add(list_entry_t* elm, list_entry_t* prev, list_entry_t* next) {
    prev->next = next->prev = elm;
    elm->next = next;
    elm->prev = prev;
}
static inline void __list_del(list_entry_t* prev, list_entry_t* next) {
    prev->next = next;
    next->prev = prev;
}

插入,删除操作,对基础操作的简单封装。

static inline void list_add(list_entry_t* listelm, list_entry_t* elm) {
    __list_add(elm, listelm, listelm->next);
}
static inline void list_del(list_entry_t* listelm) {
    __list_del(listelm->prev, listelm->next);
}

由于 l i s t _ e n t r y _ t list\_entry\_t list_entry_t类型指针为通用指针,无法通过其访问特定数据类型中的数据。
因此需要将其转化成特定数据类型指针。

#define offsetof(type, member)                                      \
((size_t)(&((type *)0)->member))

#define to_struct(ptr, type, member)                               \
((type *)((char *)(ptr) - offsetof(type, member)))

// 宏定义,将list_entry_t类型指针转化为特定类型指针,用于访问特定类型中的数据
#define le2myType(le, member)                 \
to_struct((le), struct myType, member)

主要需要使用到以上三个宏。
o f f s e t o f offsetof offsetof用于求出 t y p e type type类型数据结构中成员 m e m b e r member member的偏移量(相对于首地址的偏移量),主要用到编译器的特性,将零地址强制转化成 t y p e type type类型。
o f f s e t o f = t y p e . m e m b e r − t y p e b a s e = t y p e . m e m b e r − 0 = t y p e . m e m b e r offsetof=type.member-typebase=type.member-0=type.member offsetof=type.membertypebase=type.member0=type.member
t o _ s t r u c t to\_struct to_struct用于将 p t r ptr ptr转化为 t y p e type type类型指针。
通过 o f f s e t o f offsetof offsetof宏可以计算出结构体中一个成员距离首地址的距离 d d d
反过来,知道这个结构体成员的地址 p t r ptr ptr以及距离 d d d,可以计算出首地址。
t y p e b a s e = t y p e . m e m b e r − o f f s e t o f = p t r − d typebase=type.member-offsetof=ptr-d typebase=type.memberoffsetof=ptrd
l e 2 m y T y p e le2myType le2myType t o _ s t r u c t to\_struct to_struct的简单封装。需要根据特定数据类型来确定。

其实如果将 l i s t _ e n t r y _ t list\_entry\_t list_entry_t类型成员作为自定义数据类型结构体中的第一个成员,那么直接强制类型转化即可,因为此时 o f f s e t o f offsetof offsetof一定为 0 0 0

下面结合一个实例来学习这种双向循环链表的使用。

#include <iostream>

using namespace std;

#include "typelist.h"

// 普通双向循环链表结构
struct myOrdinaryType {
    int data;
    struct myOrdinaryType *prev, *next;
};

// 通用双向循环链表结构
struct myType{
    int data;
    list_entry_t list_entry;
};

// 宏定义,将list_entry_t类型指针转化为特定类型指针,用于访问特定类型中的数据
#define le2myType(le, member)                 \
to_struct((le), struct myType, member)


// 遍历链表
void printList(list_entry_t* le){
    if(list_empty(le)){
        return;
    }

    list_entry_t* it = le;
    while((it=list_next(it)) != le){
    	// 利用le2myType宏,将list_entry_t类型指针转化为struct myType类型指针
        struct myType *p = le2myType(it, list_entry);
        std::cout << p->data << " ";
    }
    std::cout << std::endl;
}


int main()
{
	// 定义一个头结点以及三个数据节点
	// 头节点中的数据并没有意义,并不会被使用,这里定义为-1无任何意义
    struct myType head; head.data = -1; 
    
    struct myType node1; node1.data = 1;
    struct myType node2; node2.data = 2;
    struct myType node3; node3.data = 3;

	// 初始化头结点
    list_init(&head.list_entry);
	
	// 将三个数据节点加入链表中
    list_add(&head.list_entry, &node1.list_entry);
    list_add(&node1.list_entry, &node2.list_entry);
    list_add(&node2.list_entry, &node3.list_entry);


	
    list_entry_t * le = &head.list_entry;  //le是空闲块链表头指针
	
	// 遍历链表,输出结果为: 1 2 3
    printList(le);
	
	// 删除第三个节点
    list_del(&node3.list_entry);
	printList(le); // 输出结果为: 1 2
    
    // 删除第二个节点
    list_del(&node2.list_entry);
    printList(le); // 输出结果为: 1
	
	// 删除第一个节点
    list_del(&node1.list_entry);
    printList(le); // 输出结果为:

    return 0;
}

内核双向循环链表完整定义

#ifndef TYPELIST_H
#define TYPELIST_H

/* Return the offset of 'member' relative to the beginning of a struct type */
#define offsetof(type, member)                                      \
((size_t)(&((type *)0)->member))

/* *
 * to_struct - get the struct from a ptr
 * @ptr:    a struct pointer of member
 * @type:   the type of the struct this is embedded in
 * @member: the name of the member within the struct
 * */
#define to_struct(ptr, type, member)                               \
((type *)((char *)(ptr) - offsetof(type, member)))


struct list_entry_t {
    struct list_entry_t *prev, *next;
};
static inline void list_init(list_entry_t* elm) __attribute__((always_inline));
static inline void list_add(list_entry_t* listelm, list_entry_t* elm) __attribute__((always_inline));
static inline void list_add_before(list_entry_t* listelm, list_entry_t* elm) __attribute__((always_inline));
static inline void list_add_after(list_entry_t* listelm, list_entry_t* elm) __attribute__((always_inline));
static inline void list_del(list_entry_t* listelm) __attribute__((always_inline));
static inline void list_del_init(list_entry_t* listelm) __attribute__((always_inline));
static inline bool list_empty(list_entry_t* list) __attribute__((always_inline));
static inline list_entry_t *list_next(list_entry_t* listelm) __attribute__((always_inline));
static inline list_entry_t *list_prev(list_entry_t* listelm) __attribute__((always_inline));

static inline void __list_add(list_entry_t* elm, list_entry_t* prev, list_entry_t* next) __attribute__((always_inline));
static inline void __list_del(list_entry_t* prev, list_entry_t* next) __attribute__((always_inline));
/* *
 * list_init - initialize a new entry
 * @elm:        new entry to be initialized
 * */
static inline void list_init(list_entry_t* elm) {
    elm->prev = elm->next = elm;
}

/* *
 * list_add - add a new entry
 * @listelm:    list head to add after
 * @elm:        new entry to be added
 *
 * Insert the new element @elm *after* the element @listelm which
 * is already in the list.
 * */
static inline void list_add(list_entry_t* listelm, list_entry_t* elm) {
    __list_add(elm, listelm, listelm->next);
}

/* *
 * list_add_before - add a new entry
 * @listelm:    list head to add before
 * @elm:        new entry to be added
 *
 * Insert the new element @elm *before* the element @listelm which
 * is already in the list.
 * */
static inline void list_add_before(list_entry_t* listelm, list_entry_t* elm) {
    __list_add(elm, listelm->prev, listelm);
}

/* *
 * list_add_after - add a new entry
 * @listelm:    list head to add after
 * @elm:        new entry to be added
 *
 * Insert the new element @elm *after* the element @listelm which
 * is already in the list.
 * */
static inline void list_add_after(list_entry_t* listelm, list_entry_t* elm) {
    __list_add(elm, listelm, listelm->next);
}

/* *
 * list_del - deletes entry from list
 * @listelm:    the element to delete from the list
 *
 * Note: list_empty() on @listelm does not return true after this, the entry is
 * in an undefined state.
 * */
static inline void list_del(list_entry_t* listelm) {
    __list_del(listelm->prev, listelm->next);
}

/* *
 * list_del_init - deletes entry from list and reinitialize it.
 * @listelm:    the element to delete from the list.
 *
 * Note: list_empty() on @listelm returns true after this.
 * */
static inline void list_del_init(list_entry_t* listelm) {
    list_del(listelm);
    list_init(listelm);
}

/* *
 * list_empty - tests whether a list is empty
 * @list:       the list to test.
 * */
static inline bool list_empty(list_entry_t* list) {
    return list->next == list;
}

/* *
 * list_next - get the next entry
 * @listelm:    the list head
 **/
static inline list_entry_t* list_next(list_entry_t* listelm) {
    return listelm->next;
}

/* *
 * list_prev - get the previous entry
 * @listelm:    the list head
 **/
static inline list_entry_t* list_prev(list_entry_t* listelm) {
    return listelm->prev;
}

/* *
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 * */
static inline void __list_add(list_entry_t* elm, list_entry_t* prev, list_entry_t* next) {
    prev->next = next->prev = elm;
    elm->next = next;
    elm->prev = prev;
}


/* *
 * Delete a list entry by making the prev/next entries point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 * */
static inline void __list_del(list_entry_t* prev, list_entry_t* next) {
    prev->next = next;
    next->prev = prev;
}

#endif // TYPELIST_H

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值