list_for_each_entry(pos, head, member)的内幕

list_for_each_entry(pos, head, member)是一个遍历链表的操作,但是从中涉及到的小函数很多,想要彻底高清除,需要下一点功夫。

下面一步一步的分解该宏定义。抽丝剥茧的看看这个宏定义到底最后定义成什么了。

#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是什么呢?恩,是它

#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

那么, list_for_each_entry最终简化成

#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上面。而这个宏定义如下:

#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类型所对应的地址么?

用如下例子可以看出

#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----%p\n",pos,&init_struct);
     
          char *ptr_ch2 = &init_struct.ch;
          pos= container_of(ptr_ch2,struct test_struct,ch);
	  printf("%p----%p\n",pos,&init_struct);

          float *ptr_ch3 = &init_struct.f1;
          pos = container_of(ptr_ch3,struct test_struct,f1);
	  printf("%p----%p\n",pos,&init_struct);

          printf("test_struct->num =%d\n",pos->num);
          printf("test_struct->ch =%c\n",pos->ch);
          printf("test_struct->ch =%f\n",pos->f1);
          return 0;
  }
得到的结果:

0xbf942ca4----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的类型第地址。以便求出里面的数据


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值