linux c 转换双指针,用C语言实现Linux风格的双向链表

双向链表,可以在链表的任何位置添加和删除元素,只需要该位置的指针。

如果是头指针,就是在首尾添加和删除。

而且,它删除元素时不需要知道链表头指针,也不需要从头指针遍历到当前位置的前一个位置,只需要当前位置的指针就行。

总的来说,双向链表远比单链表灵活,特别适合需要频繁增加和删除的场景。

随着Linux的流行,Linux内核风格的双向链表(把链表嵌在数据结构里)也流行了起来。

这个实现还是很简单的,代码如下:

定义两个指针,prev和next分别指向前一个和后一个元素,组成双向链表。

整个链表挂在链表头上,链表头也是一个链表元素,但是它没有附加的数据部分。

链表头除了作为整个链表的挂载点之外,就是充当哨兵节点,提示遍历链表时的起始位置。

7a2393d11fccc70cb6500b33f75935ea.png

这种双向链表的for循环,一般是这么写的:

for (l = scf_list_head(h); l != scf_list_sentinel(h); l = scf_list_next(l)) {

// 其他代码

实际上,h的下一个元素(h->next)才是链表的第一个元素,最后一个元素是h->prev,h则是哨兵节点。

为了避免出错,一般把它们写成宏,见下图。

dec00ce2458ca7c5e9c965b884f323a9.png

获取链表元素的数据部分的指针,使用宏scf_list_data(l, type, member)。

其中l是链表元素的指针,type是数据部分的类型,member则是链表元素在数据类型里的变量名。

例如可以这么定义一个类型:

typedef struct {

scf_list_t list;

int d;

} scf_word_t;

member就是list,type就是scf_word_t,根据链表元素的指针l以及链表元素在数据类型里的偏移量,就可以算出数据的指针。

scf_list_data()必须写成宏,而不能像scf_list_add_front()和scf_list_add_tail()一样写成内联函数,因为宏可以直接替换源代码,而这里需要直接替换源代码。

在C和C++中,有些场景必须使用宏才可以,而没法使用内联函数。

例如,给一个类添加动态创建功能,这是当年微软MFC的机制之一,也是用宏来实现的,而没法用内联函数。

动态创建,是在代码运行时根据实时获取的类名字符串,来调用类的构造函数创建类的对象。

当然没法把字符串当作构造函数来用:在源代码文件里,new Object()会创建一个类的对象,但是new "Object"()是语法错误。但是在运行时,只能拿得到"Object",需要根据它去找到构造函数Object()。

以后写篇文章说一下C++的动态创建。

根据内嵌链表元素的指针,获取数据结构的指针,也是必须使用宏的场景之一,因为member也是数据结构里的一个成员变量名:既不是指针,也不是字符串,只有在编译阶段才会被解释为成员变量。

宏替换的处理,是在编译之前。

scf_list_data的实现如下:

offsetof(type, member)用于获取member在type里的偏移量,它的实现:

(size_t)(&((type*)0)->member)

就是把整数0转化为type*指针,这样((type*)0)->member的地址(再转化为整数)就是偏移量。

C库本身是带这个宏函数的,不需要自己去写。

2d174b17db98fc6ec07f3ac14e92d177.png

想了解更多精彩内容,快来关注闲聊代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值