博客
关于我
linux 获取链表节点数,LINUX基础-list链表
阅读量:791 次
发布时间:2023-02-02

本文共 1768 字,大约阅读时间需要 5 分钟。

linux链表

在研究linux内核或基于linux的代码时,我们常会遇到LIST_HEAD、INIT_LIST_HEAD等宏定义,以及list_for_each、list_entry等函数。本文将介绍这些常用宏定义和函数的意义。

struct list_head

在linux中,链表采用双向循环链表结构,定义如下:

struct list_head{struct list_head *next, *prev;}

需要注意的是,链表节点中并不存储数据域。与linux内核中的KObjetc类似,链表节点是嵌入在数据结构中的。这类结构在内核中较为普遍,主要用于链表操作的一种轻量级实现方式。

初始化链表

初始化一个链表节点需要使其自身的prev和next指针都指向自己。有两种常见方法:

  • LIST_HEAD(name);
  • 跟define 宏:

    #define INIT_LIST_HEAD(name) { &(name), &(name) }

    或者直接声明变量:

    struct list_head name = INIT_LIST_HEAD(name);

    这种初始化方式让节点自身环环相扣,成为一个自己的循环链表。

    1. INIT_LIST_HEAD(ptr);
    2. 这是一个宏定义,展开为:

      do {(ptr->next) = (ptr);(ptr->prev) = (ptr);} while (0);

      前提是ptr必须先申明为struct list_head类型。这两种方式在功能上没有区别,只在使用方式上有细微差别。

      链表遍历

    3. list_for_each
    4. 定义:

      #define list_for_each(pos, head)for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next)

      __list_for_each

      #define __list_for_each(pos, head)for (pos = (head)->next; pos != (head); pos = pos->next)

      两者的区别在于是否带有prefetch。前者为了提高遍历效率进行预取操作,而后者则是简单的遍历。有时为了发挥性能优势,我们需要使用带有prefetch的版本。

      1. list_for_each_safe
      2. for (pos = (head)->next, n = pos->next; pos != head; pos = n, n = pos->next)

        这种遍历方式不同于list_for_each,主要是为了在遍历过程中能够安全地删除节点。list_for_each不能在循环体内删除节点,而list_for_entry则可能导致死循环或panic错误。因而在需要删除的场合,应该使用list_for_each_safe。

        list_entry函数

        list_entry(pos, type, member)

        该函数用于根据链表指针找到包含该指针的数据结构体。它实际上就是container_of函数的另一种表达方式。container_of函数通常用于 Shoblemaker结构体与其链表指针之间的转换。

        list_for_each_entry

        这个宏定义的作用是将list_for_each_entry和list_entry结合起来,以便更方便地同时获取链表节点和数据结构体。它的进一步扩展:

        #define list_for_each_entry(pos, head, member)for (pos = list_entry( (head)->next, typeof(*pos), member );prefetch(pos->member->next), &pos->member != head;pos = list_entry(pos->member->next, typeof(*pos), member))

        这个递归式的定义方式在语言实现上有些特殊表现,需要仔细理解其对->符号的处理。

        总之,理解这些链表处理宏定义和函数,是掌握linux内核链表操作的重要第一步。熟练掌握这些技巧在实际编写代码时能够发挥重要作用。

    转载地址:http://newfk.baihongyu.com/

    你可能感兴趣的文章
    Linux 进程信号的基本概念、信号类型、信号处理方式、信号传递机制以及如何使用进程信号进行进程间通信、异常处理
    查看>>
    Linux 进程和系统监测
    查看>>
    linux 进程控制入门
    查看>>
    Linux 进程管理及监控与性能评估
    查看>>
    Linux 进程管理详解
    查看>>
    Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知...
    查看>>
    linux 通过inode删除文件
    查看>>
    Linux 通过SSH跳板机实现端口转发
    查看>>
    Linux 通过压缩包安装 MySQL 并设置远程连接教程
    查看>>
    Linux 通过监控系统内存并定时重启指定服务
    查看>>
    Linux 逻辑卷详解
    查看>>
    Linux 部署ASP.NET SQLite 应用 的坎坷之旅 附demo及源码
    查看>>
    linux 配置 skywalking
    查看>>
    linux 配置 vsftpd 匿名用户可增加、修改、删除文件
    查看>>
    linux 重启服务脚本,常见的linux上的服务重启脚本
    查看>>
    Linux 重置root密码和修改用户密码
    查看>>
    Linux 问题故障定位的技巧大全
    查看>>
    Linux 问题故障定位(非常详细)零基础入门到精通,收藏这一篇就够了
    查看>>
    linux 防火墙操作
    查看>>