真正精彩的地方到了,这个宏以及下面的几个宏的定义,我感觉很精彩!有些地方初次理解起来比较费力,我在这里为大家慢慢分享下我的理解,不一定对,有错误的地方希望大家赐教!不罗嗦了,我们看上面这个宏,这其实就是一个宏定义的转移,利用container_of这个宏定义了上句的list_entry这个宏,我们还是不懂意思,不急。我们在kernel.h里面找到container_of这个宏的定义:
最外面的括号里面分为两部分:(size_t) 和 & ((TYPE *)0)->MEMBER,我们首先看& ((TYPE *)0)->MEMBER,它由两部分组成,&和 ((TYPE *)0)->MEMBER,我们先看后者((TYPE *)0)->MEMBER,他首先将0强制类型转换成指向TYPE类型的结构体的指针,然后引用其MEMBER成员。可能有些人不懂,这样,我们来随便定义一个TYPE类型的结构体:
这样看起来是不是一目了然,现在我们来看offsetof的意思,很简单就是:首先将0强制类型转换成指向TYPE类型的结构体的指针,然后取其MEMBER成员的地址,最后再强制类型转换成size_t行,即(unsigned int)型!那么有人会问了,为什么要使用0呢?要它的MEMBER成员的地址有什么用呢?用处很大,而且很巧!我们需要慢慢品尝:
首先,我们回顾下,什么叫指针?指针就是一个内存单元的地址!那么好,我们上面说到了,将0强制转换成TYPE类型结构体的指针,那么我们来说说,这个所指的结构体的起始地址是多少?理所当然是0.那么很好,既然它的起始地址是0,那么它的MEMBER成员的地址,其实就是它在这个结构体的偏移量!理解了吗?OK!offsetof(TYPE, MEMBER)的意义我们知道了,就是求TYPR类型的结构体中MEMBER成员的偏移量!它的作用,我们继续往下看:
这个宏的意思是不是很简单了,就是已知type类型的结构体中member成员的指针后,我们 可以求得它所在的链表的下一个指针所指的member所在的type类型的结构体的起始地址!
367 #define __list_for_each(pos, head) \
368 for (pos = (head)->next; pos != (head); pos = pos->next)
这个函数和上面的函数大同小异,功能相同,只是它没有预取下一个要遍历的节点!所以效率上差点!所以它比较适合节点数比较少的链表!
375 #define list_for_each_prev(pos, head) \
376 for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
377 pos = pos->prev)
看完上面的函数,这个就比较简单,它也是从head节点开始(不包括head节点)向前遍历每一个节点!即从链表的尾部开始遍历!
385 #define list_for_each_safe(pos, n, head) \
386 for (pos = (head)->next, n = pos->next; pos != (head); \
387 pos = n, n = pos->next)
这个应该也没有难度,只是操作更加安全,它用n先将下一个要遍历的节点保存起来,防止程序中删除本节点后,无法找到下一个节点,而出现错误!
395 #define list_for_each_prev_safe(pos, n, head) \
396 for (pos = (head)->prev, n = pos->prev; \
397 prefetch(pos->prev), pos != (head); \
398 pos = n, n = pos->prev)
这个应该也没有难度,只是操作更加安全,它用n先将下一个要遍历的节点保存起来,防止程序中删除本节点后,无法找到下一个节点,而出现错误!
406 #define list_for_each_entry(pos, head, member) \
407 for (pos = list_entry((head)->next, typeof(*pos), member); \
408 prefetch(pos->member.next), &pos->member != (head); \
409 pos = list_entry(pos->member.next, typeof(*pos), member))
又是一个很长的宏定义!我们一句一句看for()里面的三条语句,第一句:pos = list_entry((head)->next, typeof(*pos), member),list_entry(ptr,type,member)宏的意思是:已知指向type类型的结构体中member成员的指针ptr的情况下,我们求出了这个结构体的起始地址,所以这里我们进行类比分析,我们已知一个结构体的类型是typeof(*pos)类型!为什么是这个类型呢?因为pos是指向某一个结构体的指针,那么*pos不就是这个结构体吗?
继而typeof(*pos)不就是这个结构体的类型吗?OK!那么这条语句的意思就是一个结构体的指针pos,以及指向它中的member成员的指针(head->next),我们求出这个结构体的起始地址,并赋予pos!即让pos指向与之相连的下一个结构体!这里有些人可能纳闷了,结构体怎么相连了?还记得我们刚开始分析struct list_head这个类型时举的例子吗?
struct student{
int id;
char name[20];
struct list_head member;
};
我们来看这个例子,结构体虽然不能相连,但是结构体中的member成员却是list_head类型的结构体,他是可以组成链表的!第三句和第一句相同!不罗嗦了!
总之,这个宏的意思就是已知指向某个结构体的指针pos,以及指向它中member成员的指针head,从下一个结构体开始向后遍历这个结构体链。
417 #define list_for_each_entry_reverse(pos, head, member) \
418 for (pos = list_entry((head)->prev, typeof(*pos), member); \
419 prefetch(pos->member.prev), &pos->member != (head); \
420 pos = list_entry(pos->member.prev, typeof(*pos), member))
原理同上,作用就是:已经指向某个结构体的指针pos,以及指向它中member成员的指针head,从下一个结构体开始向前遍历这个结构体链。
430 #define list_prepare_entry(pos, head, member) \
431 ((pos) ? : list_entry(head, typeof(*pos), member))
这个宏比较简单,它就是判断pos这个指针是否为空,为空的话给它赋值list_entry(head, typeof(*pos), member)这条语句求出来的结构体的地址!具体的求法看上面的分析!
442 #define list_for_each_entry_continue(pos, head, member) \
443 for (pos = list_entry(pos->member.next, typeof(*pos), member); \
444 prefetch(pos->member.next), &pos->member != (head); \
445 pos = list_entry(pos->member.next, typeof(*pos), member))
这句话的分析基本和上面那个相同,它的意思就是:已知指向某个结构体的指针pos,以及指向它中的member成员的head指针,从它的下一个结构体开始向后遍历这个结构体链!
456 #define list_for_each_entry_continue_reverse(pos, head, member) \
457 for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
458 prefetch(pos->member.prev), &pos->member != (head); \
459 pos = list_entry(pos->member.prev, typeof(*pos), member))
这个函数和上面的函数基本相同,只是它是向前遍历,即从结构体链的尾部开始遍历!
469 #define list_for_each_entry_from(pos, head, member) \
470 for (; prefetch(pos->member.next), &pos->member != (head); \
471 pos = list_entry(pos->member.next, typeof(*pos), member))
这个函数和上面的函数基本相同,只是它是从前向后遍历,而且从pos所指的节点开始!(包括pos所指的节点!)
480 #define list_for_each_entry_safe(pos, n, head, member) \
481 for (pos = list_entry((head)->next, typeof(*pos), member), \
482 n = list_entry(pos->member.next, typeof(*pos), member); \
483 &pos->member != (head); \
484 pos = n, n = list_entry(n->member.next, typeof(*n), member))
这个安全的函数和上面的安全函数大同小异!原理相同,都是先保存下一个要遍历的节点!防止本节点被删除,下一节点无法访问,导致错误!
496 #define list_for_each_entry_safe_continue(pos, n, head, member) \
497 for (pos = list_entry(pos->member.next, typeof(*pos), member), \
498 n = list_entry(pos->member.next, typeof(*pos), member); \
499 &pos->member != (head); \
500 pos = n, n = list_entry(n->member.next, typeof(*n), member))
原理同上,不罗嗦了!只是增加了一个指向结构体的指针,在for()里面的第一句就赋值给他让它指向pos的下一个结构体!也是处于安全考虑!
512 #define list_for_each_entry_safe_from(pos, n, head, member) \
513 for (n = list_entry(pos->member.next, typeof(*pos), member); \
514 &pos->member != (head); \
515 pos = n, n = list_entry(n->member.next, typeof(*n), member))
和上面基本一样,只是上面是从pos所指的下一个结构体开始,这个是从pos所指的结构体开始!
527 #define list_for_each_entry_safe_reverse(pos, n, head, member) \
528 for (pos = list_entry((head)->prev, typeof(*pos), member), \
529 n = list_entry(pos->member.prev, typeof(*pos), member); \
530 &pos->member != (head); \
531 pos = n, n = list_entry(n->member.prev, typeof(*n), member))
和上一个基本相似,只是这个函数是向前开始遍历结构体,即从链的尾部开始遍历!
到此为止,list.h中的双向循环链表逐句分析结束!可能有很多错误的地方,希望大家指正!
在此和大家分享一下我的第一次看源码的心得吧,刚开始,记得是星期一的时候,陈老师刚说了这个事情,我就开始看了,说实话,我刚开始打开list.h有种头晕的感觉,那么多的代码,英文的注释!太恐怖了,但是当我看晚第一个结构体list_head的时候,我的兴趣上来了,它为什么这么定义呢?我往下看,不懂的地方不管,大概浏览一边,我就知道这个头文件是个定义了很多链表操作的头文件,那么第二遍,第三遍,第四遍.......慢慢的,一个一个函数我懂了,一边网上查,一边自己拿着笔画函数的链表,进行模拟操作,这样我们就可以清楚的知道,每一步的含义!就这样,list.h中的双向链表部分已经基本清楚了!
希望大家能一起分享,一起进步!
加油!