您的位置:首页 > 编程语言 > C语言/C++

C语言的通用链表

2015-04-11 22:28 183 查看
在操作系统编程中, 往往是使用C语言, 但C使用起来极为痛苦, 不像C++有方便的STL模板库使用。

linux内核中,有一套非常神奇的通用链表结构,能够方便的使用,管理各种类型的数据,我们今天就来研究一下,内核中的C数据结构。

本文参考:【深入分析 Linux 内核链表】

首先,我们的目标是构建一个循环双链表结构,为何是双链表,还要循环,当然是从易用性考虑了,双链表能够方便的得知自己的上一个元素,在内核中管理数据更为方便。

其一般结构大概是这样:



实现机制

首先定义一个list_node结构,用来保存链表节点信息:

/**
* @brief 链表节点结构
*/
typedef struct _list_node
{
struct _list_node   *next;
struct _list_node   *prev;
} list_node;


然后用一个存放数据的结构,比如我们要用int型的链表,如下定义:

/**
* @brief 数据存放结构
*/
typedef struct _Int_List
{
list_node   node;
int         data;
} Int_List;


这和我们传统的链表实现思路好像不大一样,我们经典的C语言链表当然是在链表中保存数据:

/**
* @brief 链表节点结构
*/
typedef ElementType     int;
typedef struct _list_node
{
struct _list_node   *next;
struct _list_node   *prev;
ElementType         data;
} list_node;


但这样的实现必然会造成链表结构被反复定义,难以实现泛型。另外一种思路可能是将ElementType实现成void*指针,然后在使用时进行强制类型转换,但这样必然会带来反复的类型转换,而且其使用相对不便。

这时要出问题了,如果数据在外层,链表在里层,那么如何从链表找到数据呢?

offsetof宏和container_of宏

为了实现从内层元素找外层元素的功能,我们需要用到这两个系统宏,一眼看上去很复杂,但实际上并不难理解。

/**
* @brief 确定当前成员变量,在结构体中偏移量的宏
*/
#ifndef offsetof
#define offsetof(type, member) ((size_t) &((type*)0)->member)
#endif


/**
* @brief 根据成员变量,找包含他的结构体指针
*/
#ifndef container_of
#define container_of(ptr, type, member) ({  \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif


这两个宏较为复杂,首先是offsetof宏,这个宏用0号指针去寻找成员变量,我们试想,如何是普通的一个结构体,C编译器如何查找其一个成员呢?

例如:

/**
* @brief 数据存放结构
*/
typedef struct _Int_List
{
list_node   node;
int         data;
} Int_List;


假设我们用
Int_List A
语句,实例化一个结构体,然后取到了A的地址0x00001000

那么node的起始地址是不是也是0x00001000

data的起始地址是不是0x00001000+data的偏移量?

那么如何我想求data的偏移量,不就是如下的代码么:

(&A)->data - (&A);


如果A的地址为0时,那么也就不用减了,就是我们宏定义中的用法。

而container_of宏也是采用类似的思路,既然找到了当前list_node成员的偏移量,那么减去偏移量,便是外层包围着的结构体的起始地址。

那好,这样我们就能实现这个链表了,但其实也不用这样费事,还有简单的办法,那就是让我们的被包含的list_node成员结构,处于我们数据存储结构的第一个位置,那么其地址就是包围其结构的地址,直接类型转换即可。

这种思路实际上也被用于C语言的继承机制的实现。

Github项目

到此,我们已经讲解了通用链表的实现思路,大家可以尝试自己实现一个独特的通用链表,具体内容就不一一赘述,我将完整的工程已经发布到了Github上面,欢迎大家前来fork测试。

【Clist项目地址】

本人才疏学浅,如有疏漏,还望指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息