说明

本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。


内容来源:  

目录:

一、list_for_each宏
1.功能简介:
2.源码及注释:
3.源文件测试理解步骤
main.c
Makefile
结果
二、list_for_each_safe宏
1.功能简介:
2.源码及注释:
3.源文件测试理解步骤
main.c
Makefile
结果
三、list_for_each_entry
1.功能简介:
2.源码及注释:
3.源文件测试理解步骤
main.c
Makefile
结果

一、list_for_each宏

1.功能简介:
  遍历双链表,不适合与遍历中进行删除节点的操作。

2.源码及注释:

 /* 
      功能:遍历head指向的头链表
      参数:
          p:指向下一个节点的链表指针 
          head:头指针
  */
#define list_for_each(p, head) \
    for ((p) = (head)->next; (p) != (head); (p) = (p)->next)

3.源文件测试理解步骤
main.c

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/* 链表节点 */
typedef struct _TestStruct
{
    struct list_head list;
    int num;
    bool pending;
    char name;
    void *pointer;
}struct_node;

static struct list_head dlist = LIST_HEAD_INIT(dlist);  /* 初始化链表: */

int main(int argc, char *argv[])
{
    struct_node *tmp = NULL;                            /* 暂存链表节点结构体 */
    struct list_head *head = &dlist;                    /* 链表表头 */
    struct list_head *p = NULL;
    int i = 0;

    //插入5个数据,使用头插法,类似于栈
    for (i = 0; i < 5; i++)
    {
        tmp = (struct_node *)malloc(sizeof(struct_node));
        tmp->num = i;
        list_add_tail(&tmp->list, head);                /* 插入链表尾部 */
    }

    /* 
        功能:遍历head指向的头链表
        参数:
            p:指向下一个节点的链表指针 
            head:头指针
    */
    list_for_each(p, head)
    {
        tmp = container_of(p, struct_node, list);
        printf("%d \n", tmp->num);
    }

    printf("------------------------------------\n");

    for ((p) = (head)->next; (p) != (head); (p) = (p)->next)
    {
        tmp = container_of(p, struct_node, list);
        printf("%d \n", tmp->num);
    }
}

Makefile

TARGET:=test
SRCS:=main.c
OBJS:=$(SRCS:.c=.o)#变量替换函数,将所有*.c文件替换为*.o文件,与OBJS=$(patsubst %.c,%.o,$(SRCS))等效

CC:=gcc#编译器
CFLAGS:=-Wall -std=gnu99#gcc选项

$(TARGET):$(OBJS)
	$(CC) -o $@ $^

clean:
	rm -rf $(TARGET) $(OBJS)

结果

xsndz@Linux:~/Desktop/list$ ./hello 
0 
1 
2 
3 
4 
------------------------------------
0 
1 
2 
3 
4 

二、list_for_each_safe宏

1.功能简介:
 遍历链表,相较于list_for_each多增加了一个中间参数,保存当前结点的下个结点,避免当前结点删除后找不到下个结点。

2.源码及注释:

/*
      功能:遍历链表(可用于删除结点)
      参数:
          p :指向下一个节点的链表指针
          n :指向p的下一个节点的链表指针
          head:头指针
  */
#define list_for_each_safe(p, n, head)                     \
    for ((p) = (head)->next, n = (p)->next; (p) != (head); \
         (p) = n, n = (p)->next)

3.源文件测试理解步骤
main.c

#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include "dlist_test.h"

/* 链表节点 */
typedef struct _TestStruct
{
    struct list_head list;
    int num;
    bool pending;
    char name;
    void *pointer;
}struct_node;

static struct list_head dlist = LIST_HEAD_INIT(dlist);  /* 初始化链表: */

int main(int argc, char *argv[])
{
    struct_node *tmp = NULL;                            /* 暂存链表节点结构体 */
    struct list_head *head = &dlist;                    /* 链表表头 */
    struct list_head *p = NULL, *n = NULL;
    int i = 0;

    //插入5个数据,使用头插法,类似于栈
    for (i = 0; i < 5; i++)
    {
        tmp = (struct_node *)malloc(sizeof(struct_node));
        tmp->num = i;
        list_add_tail(&tmp->list, head);                /* 插入链表尾部 */
    }

    /*
        功能:遍历链表(可用于删除结点)
        参数:
            p :指向下一个节点的链表指针
            n :指向p的下一个节点的链表指针
            head:头指针
    */
    // for ((p) = (head)->next, n = (p)->next; (p) != (head); (p) = n, n = (p)->next)
    list_for_each_safe(p,n,head)
    {
        tmp = list_entry(p, struct_node, list);        /* 等价于container_of */

        if (tmp->num == 1)
        {
            list_del(p);
            free(p);
        }
    }
    
    list_for_each(p, head)
    {
        tmp = container_of(p, struct_node, list);
        printf("%d \n", tmp->num);
    }
}

Makefile
与上面一致

结果

xsndz@Linux:~/Desktop/list$ ./test 
0 
2 
3 
4 

三、list_for_each_entry

1.功能简介:
  遍历链表的同时可同时获取对应链表的数据结点。

2.源码及注释:

/****** 遍历链表的同时获得结构体指针 ******/
#define list_for_each_entry(p, h, field)                 \
    for ((p) = list_first_entry(h, typeof(*(p)), field); \
         &(p)->field != (h);                             \
         (p) = list_entry((p)->field.next, typeof(*(p)), field))

3.源文件测试理解步骤
main.c

#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include "dlist_test.h"

/* 链表节点 */
typedef struct _TestStruct
{
    struct list_head list;
    int num;
    bool pending;
    char name;
    void *pointer;
}struct_node;

static struct list_head dlist = LIST_HEAD_INIT(dlist);  /* 初始化链表: */

int main(int argc, char *argv[])
{
    struct_node *tmp;                                   /* 暂存链表节点结构体 */
    struct list_head *head = &dlist;                    /* 链表表头 */
    int i = 0;

    //插入5个数据,使用头插法,类似于栈
    for (i = 0; i < 5; i++)
    {
        tmp = (struct_node *)malloc(sizeof(struct_node));
        tmp->num = i;
        list_add_tail(&tmp->list, head);                /* 插入链表尾部 */
    }

    /*
        功能:遍历链表
        参数:
            tmp:用于存储链表结点
            head:头指针
            list:节点中链表的指针
    */
    list_for_each_entry(tmp, head, list)
    {
        printf("%d\n",tmp->num);
    }
}

Makefile
与上面一致。

结果

xsndz@Linux:~/Desktop/list$ ./test 
0 
1
2 
3 
4