list_for_each_entry(pos, head, member)是一个遍历链表的操作,但是从中涉及到的小函数很多,想要彻底高清除,需要下一点功夫。
下面一步一步的分解该宏定义。抽丝剥茧的看看这个宏定义到底最后定义成什么了。
复制代码
1
2
3
4#define list_for_each_entry(pos, head, member) for (pos = list_entry((head)->next, typeof(*pos), member); &pos->member != (head); pos = list_entry(pos->member.next, typeof(*pos), member))
宏定义如上,里面关键的宏定义 list_entry是什么呢?恩,是它
复制代码
1
2#define list_entry(ptr, type, member) container_of(ptr, type, member)
那么, list_for_each_entry最终简化成
复制代码
1
2
3
4#define list_for_each_entry(pos, head, member) for (pos = container_of((head)->next, typeof(*pos), member); &pos->member != (head); pos = container_of(pos->member.next, typeof(*pos), member))
好了,可以看出,整个宏定义的关键就在于 container_of上面。而这个宏定义如下:
复制代码
1
2
3#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})
这个定义看起来特别复杂,但是一步一步展开后,它原理特别简单。分析以下分为两步( 注意:其中member是type类型中的一个变量,还有ptr是指向member类型的指针)
1:定义一个*__mptr等于ptr。其中typeof的作用就是不用定义类型直接可以推断出此类型,详细信息可以到网上搜一下。
2:根据offsetof(type,member) 是求偏移量的。然后用*__mptr减去偏移量。那不就是结构体type类型所对应的地址么?
用如下例子可以看出
复制代码
得到的结果:
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#include <stdio.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );}) struct test_struct { int num; char ch; float f1; }; int main(void) { struct test_struct *pos; struct test_struct init_struct ={12,'a',12.3}; int *ptr_ch1 = &init_struct.num; pos = container_of(ptr_ch1,struct test_struct,num); printf("%p----%pn",pos,&init_struct); char *ptr_ch2 = &init_struct.ch; pos= container_of(ptr_ch2,struct test_struct,ch); printf("%p----%pn",pos,&init_struct); float *ptr_ch3 = &init_struct.f1; pos = container_of(ptr_ch3,struct test_struct,f1); printf("%p----%pn",pos,&init_struct); printf("test_struct->num =%dn",pos->num); printf("test_struct->ch =%cn",pos->ch); printf("test_struct->ch =%fn",pos->f1); return 0; }
复制代码
可知我们的思路是正确的。
1
2
3
4
5
60xbf942ca4----0xbf942ca4 0xbf942ca4----0xbf942ca4 0xbf942ca4----0xbf942ca4 test_struct->num =12 test_struct->ch =a test_struct->ch =12.300000
一般条件下,调用函数中的member为list_head类型,那list_for_each_entry的函数就可以用以下内容概括了:
即根据list_head的遍历找出下一个list_head。然后推断出整个pos的类型第地址。以便求出里面的数据
最后
以上就是微笑蓝天最近收集整理的关于list_for_each_entry(pos, head, member)的内幕的全部内容,更多相关list_for_each_entry(pos,内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复