看看上面的代码,我们做的基本工作都有那些呢?
1、定义了一个宿主结构体stu,并且在宿主结构体中我们定义了一个struct list_head 类型的list变量;
2、定义一个头结点并且对其进行初始化工作;
3、对定义的一个宿主结构体变量申请内存空间;
4、对申请的宿主结构体变量初始化和添加到以stu_list为头结点的链表中。
在上面值得注意的就是list_for_each()和list_entry(),我们会在接下来的部分讲解,读者在这儿只需要知道它们两个在此合在一起的作用就是打印出宿主结构stu中每个数据。sprintf()的使用就不在这里讲解了,很简单,相信读者猜都可以猜出它的功能。读者如果一开始对上面的文字描述部分有什么疑惑或者不解的现在看了代码的实现应该都懂了,list_add_tail()的使用和list_add()类似,读者可以自己修改代码实现。如果一开始对于list_add()不太理解的读者,现在对于list_add()的理解现在可以参考运行结果和上面的文字描述部分。
我们接着往下看。
|
在prev和next指针所指向的结点之间,两者互相所指。其实也就是prev为待删除的结点的前面一个结点,next为待删除的结点的后面一个结点。
|
删除entry所指的结点,同时将entry所指向的结点指针域封死。在这里值得注意的是LIST_POISON1、LIST_POISON2。它们在list.h中的宏定义如下:
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
对LIST_POISON1、LIST_POISON2的说明,Linux 内核中有这么一句话:These are non-NULL pointers that will result in page faults under normal circumstances,used to verify that nobody uses non-initialized list entries。也就是说它们并不是空指针,但是访问这样的指针在正常情况下是会导致出错的。其实按照我们一般的思路都是把entry->next 和entry->prev 赋值为NULL,使得不可以通过该节点进行访问。但是在这里使用了一种特殊的方法。注意:我在linux环境下以上宏的值不用修改是不会出错的,但是在vc下就会出错,不允许使用那两个值,所以要修改为NULL。
|