通常写个链表,基本上是如下的样子
struct Person
{
char m_szName[24];
Person *m_pNext; //指向下一个
Person *m_pFront; //指向前一个
};
换言之,有N个数据类型,就有N个链表
今天在Linux的学习中,学习到了Linux中链表的方式
struct list_head
{
list_head *m_pFront;
list_head *m_pNexe;
};
struct name_info
{
char m_szName[28];
list_head listhead; //链表
};
Linux将链表抽象出来作为一个对象,塞入到具体的数据当中,这样一来: 不同的数据可以用同一条链表串联起来。具体的实现是如何呢?关键就在于当我们拿到链表的时候,我们知道这个链表就存在于数据中,如何在链表中由具体的某一个节点获取当前它所在数据。换言之,知道节点listheadX, 这个X必在某个数据当中,拿到数据就行了。
解决方案很简单,根据结构体的内存布局,我们可以反向的由链表元素的地址推算出数据的首地址。公式:数据首地址 + 链表元素的偏移值 = 链表元素的地址,
数据首地址 = 链表元素的地址 - 链表元素的偏移值;至此问题就迎刃而解了。
自定义了一个宏,
#define GetNameInfo(type,instance,member) (type*)((char*)(&instance) - (char*)(&((type*)0)->member))
宏展开就是一个表达式,-号左边就是链表地址了,-号右边就是链表在数据当中的偏移值。
原理很简单,就是-号右边略有点绕,就是令0为数据的首地址,(实际上是不可能的,但是在此我们可以这么写,因为仅仅是取地址操作,没有涉及到引用,所以不会崩),然后具体的数据域再取地址,那么就是偏移无疑了。
至此,由链表获取数据首地址的问题解决了,这种链表也就会用了。
以上两种链表,仁者见仁,智者见智,觉得哪个用着顺手就用哪个吧