struct list_head结构体及相关函数

struct list_head结构体是linux实现数据结构双向链表的基础。其定义:

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

可见链表里面的成员还是链表,每个链表都指向了前面和后面的链表。

一般将struct list_head作为一个成员,放到一个结构体中,其作用是可以从当前的结构体指针,获取到下一个链表元素的地址。一般用list_entry()来实现。具体按照下面的链接:

http://www.cnblogs.com/bastard/archive/2012/10/19/2731107.html

ok,下面来看看list_head为我们提供的一些接口:

先看一个基础的:

添加add:

static inline void __list_add(struct list_head *new,
         struct list_head *prev,
         struct list_head *next)
{
 next->prev = new;
 new->next = next;
 new->prev = prev;
 prev->next = new;
}

这是在原来的链表中添加一个元素。两个接口,一个是添加为当前list_head的next,一个是添加到prev。对应的函数分别为:list_add和list_add_tail.

static inline void list_add(struct list_head *new, struct list_head *head)
{
 __list_add(new, head, head->next);
}

static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
 __list_add(new, head->prev, head);
}

如果不好理解的话,自己画个图,应该就能明白了。

删除delet:

static inline void __list_del(struct list_head * prev, struct list_head * next)
{
 next->prev = prev;
 prev->next = next;
}

static inline void __list_del_entry(struct list_head *entry)
{
 __list_del(entry->prev, entry->next);
}

static inline void list_del(struct list_head *entry)
{
 __list_del(entry->prev, entry->next);
 entry->next = LIST_POISON1;
 entry->prev = LIST_POISON2;
}

static inline void list_del_init(struct list_head *entry)
{
 __list_del_entry(entry);
 INIT_LIST_HEAD(entry);
}

删除就是把某一节点从链表中删除。entry->next = LIST_POISON1; entry->prev = LIST_POISON2; LIST_POISON1/2在linux/poison.h中定义。删除后,为什么还要设置删除掉的节点指针呢?因为删除后,该选节点已不在链表当中,因此不会再使用。LIST_POISON1/2是两个不会存在于内核空间的地址,如果使用,就会报错。因此,设置指针,是强制禁用该节点。

inline void list_del_init 把entry从链表中delete,并将其初始化为一个空的链表。

替代replace:

static inline void list_replace(struct list_head *old,
    struct list_head *new)
{
 new->next = old->next;
 new->next->prev = new;
 new->prev = old->prev;
 new->prev->next = new;
}

static inline void list_replace_init(struct list_head *old,
     struct list_head *new)
{
 list_replace(old, new);
 INIT_LIST_HEAD(old);
}

移动move:

/**
 * list_move - delete from one list and add as another‘s head
 * @list: the entry to move
 * @head: the head that will precede our entry
 */
static inline void list_move(struct list_head *list, struct list_head *head)
{
 __list_del_entry(list);
 list_add(list, head);
}

/**
 * list_move_tail - delete from one list and add as another‘s tail
 * @list: the entry to move
 * @head: the head that will follow our entry
 */
static inline void list_move_tail(struct list_head *list,
      struct list_head *head)
{
 __list_del_entry(list);
 list_add_tail(list, head);
}

从原链表中删除,并添加到新的链表中。list_move添加到head后面,list_move_tail添加到head的前面。

//将head和它的next互换

static inline void list_rotate_left(struct list_head *head)
{
 struct list_head *first;

if (!list_empty(head)) {
  first = head->next;
  list_move_tail(first, head);
 }
}

/**
 * list_is_singular - tests whether a list has just one entry. //测试是否只有一个节点,除了头节点外。
 * @head: the list to test.
 */
static inline int list_is_singular(const struct list_head *head)
{
 return !list_empty(head) && (head->next == head->prev);
}

链表一分为二cut:

static inline void __list_cut_position(struct list_head *list,
  struct list_head *head, struct list_head *entry)
{
 struct list_head *new_first = entry->next;
 list->next = head->next;
 list->next->prev = list;
 list->prev = entry;
 entry->next = list;
 head->next = new_first;
 new_first->prev = head;
}

static inline void list_cut_position(struct list_head *list,
  struct list_head *head, struct list_head *entry)
{
 if (list_empty(head))
  return;
 if (list_is_singular(head) &&
  (head->next != entry && head != entry))
  return;
 if (entry == head)
  INIT_LIST_HEAD(list);
 else
  __list_cut_position(list, head, entry);
}

注意这个是从entry处分开,list到entry为新的链表。head、entry->next、、、为老的链表。

举例:原来的链表是 head->1->2->3->4->5(只列出next方向,previous方向就是反过来),如果entry是2,那么新的链表是list->1->2,原来的链表则变为head->3->4->5。

看代码的一些小心得:一,阅读英文注释,不要害怕。二,静下心。

时间: 2024-08-04 20:14:16

struct list_head结构体及相关函数的相关文章

Linux中表示“时间”的结构体和相关函数

转载于:http://blog.chinaunix.net/uid-25909722-id-2827364.html Linux中表示“时间”的结构体和相关函数 2011-09-13 17:01:13 分类: C/C++ 在Linux系统中,表示“时间”概念的结构体有多个,相关的时间处理函数也有很多,给人以很混乱的感觉.导致了当我们真正要使用这些结构体和函数的时候,却不知道到底该用哪个结构体和哪些函数.有必要加以归纳总结一下.通过查看头文件/usr/include/time.h 和 /usr/i

struct ifreq结构体与ip,子网掩码,网关等信息

总结一下,今天学习的关于通过socket,ioctl来获得ip,netmask等信息,其中很多内容参照了很多网上的信息,我会一一列出的 我用的这个函数,就是下面这个函数,其中的有一些全局变量,很好懂,也就不多做解释了一.下面对这个函数进行注解一下: int get_nic_IP_Address()//获取各网卡IP地址.子网掩码{ struct ifreq ifreq;  //声明一个struct ifreq结构体(这个结构体中有很多重要的参数,具体可以参照第二的补充)   int sock; 

struct sk_buff结构体详解

struct sk_buff是linux网络系统中的核心结构体,linux网络中的所有数据包的封装以及解封装都是在这个结构体的基础上进行. struct sk_buff_head  {     struct sk_buff *next;     struct sk_buff *prev;          __u32 qlen;     spinlock_t lock; } struct sk_buff {     struct sk_buff *next;     struct sk_buff

struct ethhdr结构体详解

    在linux系统中,使用struct ethhdr结构体来表示以太网帧的头部.这个struct ethhdr结构体位于#include<linux/if_ether.h>之中. #define ETH_ALEN 6  //定义了以太网接口的MAC地址的长度为6个字节 #define ETH_HLAN 14  //定义了以太网帧的头长度为14个字节 #define ETH_ZLEN 60  //定义了以太网帧的最小长度为 ETH_ZLEN + ETH_FCS_LEN = 64个字节 #d

struct socket结构体详解

在内核中为什么要有struct socket结构体呢?    struct socket结构体的作用是什么?    下面这个图,我觉得可以回答以上两个问题.      由这个图可知,内核中的进程可以通过使用struct socket结构体来访问linux内核中的网络系统中的传输层.网络层.数据链路层.也可以说struct socket是内核中的进程与内核中的网路系统的桥梁.   struct socket {      socket_state  state; // socket state  

linux内核中的struct rlimit结构体详解

   在linux内核中,对一个进程获取系统资源的数量进行了限制.那么linux内核是如何实现这种对一个进程的各种资源的限制呢?    linux使用struct rlimit结构体来实现的,rlimit是 resource limit的缩写.    struct rlimit           {               unsigned int rlim_cur;  /* soft limit */               unsigned int rlim_max;  /* ha

struct in_addr 结构体

struct in_addr 结构体: struct in_addr { in_addr_t s_addr; }; 表示一个32位的IPv4地址. in_addr_t一般为32位的unsigned int,其字节顺序为网络字节序,即该无符号数采用大端字节序.其中每8位表示一个IP地址中的一个数值. 打印的时候可以调用inet_ntoa()函数将其转换为char*类型. 头文件为:#include <arpa/inet.h> inet--ntoa()函数用于将一个十进制网络字节序转换为点分十进制

typedef struct与struct定义结构体

今天在定义结构体的时候发现typedef struct与struct定义结构体有一些不同之处: 结构也是一种数据类型, 可以使用结构变量, 因此,  象其它 类型的变量一样, 在使用结构变量时要先对其定义. 定义结构变量的一般格式为: struct 结构名 { 类型  变量名; 类型  变量名; ... } 结构变量; 结构名是结构的标识符不是变量名. 另一种常用格式为: typedef struct 结构名 { 类型  变量名; 类型  变量名; ... } 结构别名; 另外注意:  在C中,

cdev结构体及其相关函数

一.在Linux2.6内核中一个字符设备用cdev结构来描述,其定义如下: 1 struct cdev { 2 struct kobject kobj; 3 struct module *owner; //所属模块 4 const struct file_operations *ops; //文件操作结构,在写驱动时,其结构体内的大部分函数要被实现 5 struct list_head list; 6 dev_t dev; //设备号,int 类型,高12位为主设备号,低20位为次设备号 7 u