Linux 内核“共享”双向链表在 linux 内核中,有大量的数据结构需要用到双向链表,例如进程、文件、模块、页面等。若采用双向链表的传统实现方式,需要为这些数据结构维护各自的链表,并且要为每个链表设计插入、删除等操作函数。因为用来维持链表的 next 和 prev 指针指向对应类型的对象,所以一种数据结构的链表操作函数不能用于操作其它数据结构的链表。而本文所提供的正是可以让多个链表共享同一套链表的操作。如下图:
我们把火车车皮当做首尾相接的链表,而火车上承载的是油罐、坦克等各种类型的元素,不管是什么类型,火车车皮都可以对其进行承载。这是个写实的例子,他的结构模型如下图:
原来的链表节点:
1 typedef struct _ConnTimeout 2 { 3 int fd; 4 time_t timeout; // 使用超时时刻的时间戳表示 5 struct _ConnTimeout* next; //下一个节点的指针域 6 struct _ConnTimeout* prev; //上一个结点的指针域 7 }ConnTimeout;
将原本的链表结构体进行拆分,将链表的双向指针域从结构体中单拆出来 DbLinkNode:
1 typedef struct _DoubleLinkNode // 一个双向链表节点“挂件” 2 { 3 struct _DoubleLinkNode* next; //下一个节点的指针域 4 struct _DoubleLinkNode *prev; //上一个结点的指针域 5 }DbLinkNode; 6 7 typedef struct 8 { 9 int fd; 10 time_t timeout; // 使用超时时刻的时间戳表示 11 DbLinkNode node; // 双向链表节点“挂件” 12 }ConnTimeout;
如何用双向链表挂件读取不同结构体中的元素呢
实现要点:
知识关联:结构体内存对齐
使用 offsetof 可以根据链表节点在结构体中的地址逆推出结构体变量的位置,如下代码:
1 #include<iostream> 2 #include<string> 3 #include<stdlib.h> 4 5 using namespace std; 6 7 typedef struct _DoubleLinkNode // 一个双向链表节点“挂件” 8 { 9 struct _DoubleLinkNode* next; //下一个节点的指针域 10 struct _DoubleLinkNode* prev; //上一个结点的指针域 11 }DbLinkNode; 12 13 typedef struct 14 { 15 int fd; 16 time_t timeout; // 使用超时时刻的时间戳表示 17 DbLinkNode node; // 双向链表节点“挂件” 18 }ConnTimeout; 19 20 int main() 21 { 22 //通过节点访问到节点承载的数据 23 ConnTimeout* ct = new ConnTimeout; 24 DbLinkNode* p = &(ct->node); 25 26 cout << "请输入超时节点对应的fd: "; 27 cin >> ct->fd; 28 cout << "\n通过链表中的节点访问节点上承载的数据:" << endl; 29 30 //offsetof 是一个宏,他的作用是将传入的节点 ConnTimeout,计算挂件 node 距离节点地址的字节数,返回一个int 赋值给 offset 31 int offset = offsetof(ConnTimeout, node); 32 33 ConnTimeout* tmp = (ConnTimeout*)((size_t)p - offset); 34 printf("offset: %d\n", offset); 35 printf("通过链表节点node访问到的数据:%d\n", tmp->fd); 36 }
通过对指针进行操作,将 tmp 指向链表节点位置,对其进行结构体类型强转后对内部进行数据访问。
===================================================================================================================
原文:https://www.cnblogs.com/CooCoChoco/p/13603295.html