android源代码学习 init中的双向链表listnode

在init源代码中双向链表listnode被使用地很多。android源代码中定义了结构体listnode,奇怪的是,这个结构体只有用于链接节点的prev和next指针,却没有任何和”数据“有关的成员变量。那么代码中如何通过一个节点来找到该节点“存储“的数据呢?关键是下面这个宏。

?
1
2
#define node_to_item \
     (container *) ((( char *) (node)) - offsetof(container, member))

      看懂了这个宏,就基本能够理解listnode的用法了。下面是一个我自己参考listnode写的小例子。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <stddef.h>
 
// listnode类型的声明,里面只有两个指针prev,next
typedef struct _listnode {
     struct _listnode *prev;
     struct _listnode *next;
} listnode;
 
// 使用listnode时最关键的宏
#define node_to_item(node, container, member) \
     (container *) ((( char *) (node)) - offsetof(container, member))
 
// 给链表添加节点
void list_add_tail(listnode *list, listnode *node)  {
     list->prev->next = node;
     node->prev = list->prev;
     node->next = list;
     list->prev = node;
}
 
// 每个listnode节点对应“存储”的数据信息,其中竟然有一个listnode类型的成员变量?
typedef struct _node {
     listnode list;
     int data;
} node;
 
// 建立一个有三个节点的双向链表,并遍历输出一遍。
int main() {
     node n1, n2, n3, *n;
     listnode list, *p;
     n1.data = 1 ;
     n2.data = 2 ;
     n3.data = 3 ;
 
     list.prev = &list;
     list.next = &list;
     list_add_tail(&list, &n1.list);
     list_add_tail(&list, &n2.list);
     list_add_tail(&list, &n3.list);
 
     for (p = list.next; p != &list; p = p->next) {
         n = node_to_item(p, node, list);
         printf( "%d\n" , n->data);
     }
     return 0 ;
}

      上面这个例子遍历了一次双向链表,输出结果是

?
1
2
3
1
2
3

      在遍历双向链表时,使用了node_to_item宏,这个宏的作用是将一个listnode指针转换成了一个指定类型的指针!这就是listnode有意思的地方。这个宏先使用offsetof函数获取到指定结构体中指定成员变量的地址偏移量,然后通过指针运算获得listnode指针变量所在结构体变量的指针。

      和教科书中的实现方法正好相反,listnode不是在节点当中声明一个指向某种数据类型的指针,而是在数据类型中加入一个指向链表节点的指针,然后通过node_to_item宏来建立链表节点与数据类型之间的联系。很有趣,可是为什么要这么做呢?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值