内核链表在用户程序中的移植和使用

基础知识

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

初始化:

#define LIST_HEAD_INIT(name) { (name)->next = (name); (name)->prev = (name);}

相比于下面这样初始化,前面初始化的好处是,处理链表的时候,不用判空了。太厉害了。

#define LIST_HEAD_INIT(name) { (name)->next = (NULL); (name)->prev = (NULL);}

 遍历链表:

/**
 * list_for_each	-	iterate over a list
 * @pos:	the &struct list_head to use as a loop cursor.
 * @head:	the head for your list.
 */
#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)

添加节点:(表头开始添加)

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
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_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

添加节点:(表尾开始添加) 

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
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_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

删除节点

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
	next->prev = prev;
	prev->next = next;
}

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

判空:

/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
static int list_empty(const struct list_head *head)
{
	return (head->next) == head;
}

基本功能就这些了

测试代码

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

#define _DEBUG_INFO
#ifdef _DEBUG_INFO
    #define DEBUG_INFO(format,...)	\
        printf("%s:%d -- "format"\n",\
        __func__,__LINE__,##__VA_ARGS__)
#else
    #define DEBUG_INFO(format,...)
#endif

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

struct rcu_private_data{
    struct list_head list;
};

struct my_list_node{
    struct list_head node;
    int number;
};

/**
 * list_for_each	-	iterate over a list
 * @pos:	the &struct list_head to use as a loop cursor.
 * @head:	the head for your list.
 */
#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)

#define LIST_HEAD_INIT(name) { (name)->next = (name); (name)->prev = (name);}

#define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({				\
	void *__mptr = (void *)(ptr);					\
	((type *)(__mptr - offsetof(type, member))); })


/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
static int list_empty(const struct list_head *head)
{
	return (head->next) == head;
}

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
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_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

/**
 * list_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
	next->prev = prev;
	prev->next = next;
}

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

static int list_size(struct rcu_private_data *p){
    struct list_head *pos;
    struct list_head *head = &p->list;
    int count = 0;
    if(list_empty(&p->list)){
        DEBUG_INFO("list is empty");
        return 0;
    }

    list_for_each(pos,head){count++;}
    return count;
}

static int show_list_nodes(struct rcu_private_data *p){
    struct list_head *pos;
    struct list_head *head = &p->list;
    int count = 0;
    struct my_list_node *pnode;

    if(list_empty(&p->list)){
        DEBUG_INFO("list is empty");
        return 0;
    }

    list_for_each(pos,head){
        pnode = (struct my_list_node*)container_of(pos,struct my_list_node,node);
        DEBUG_INFO("pnode->number = %d",pnode->number);
        count++;
    }
    return count;
}

int main(int argc, char **argv){

    int i = 0;
    static struct my_list_node * new[6];
    struct rcu_private_data *p = (struct rcu_private_data*)malloc(sizeof(struct rcu_private_data));
    LIST_HEAD_INIT(&p->list);
    DEBUG_INFO("list_empty(&p->list) = %d",list_empty(&p->list));

    for(i = 0;i < 3;i++){
        new[i] = (struct my_list_node*)malloc(sizeof(struct my_list_node));
        LIST_HEAD_INIT(&new[i]->node);
        new[i]->number = i;
        list_add(&new[i]->node,&p->list);
    }

    for(i = 3;i < 6;i++){
        new[i] = (struct my_list_node*)malloc(sizeof(struct my_list_node));
        LIST_HEAD_INIT(&new[i]->node);
        new[i]->number = i;
        list_add_tail(&new[i]->node,&p->list);
    }


    //输出链表节点数
    DEBUG_INFO("list_size(&p->list) = %d",list_size(p));

    //遍历链表
    show_list_nodes(p);
    //删除指定节点
    list_del(&new[3]->node);
    
    DEBUG_INFO("list_size(&p->list) = %d",list_size(p));
    //遍历链表
    show_list_nodes(p);

    
    for(i = 0;i < 6;i++){list_del(&new[i]->node);}

    DEBUG_INFO("list_size(&p->list) = %d",list_size(p));
    //遍历链表
    show_list_nodes(p);

    for(i = 0;i < 6;i++){free(new[i]);}
    free(p);
    return 0;
}

 编译

gcc -o app app.c

执行结果:

 小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/53190.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

iTOP-RK3568开发板Docker 安装 Ubuntu 18.04

Docker 下载安装 Ubuntu18.04&#xff0c;输入以下命令&#xff1a; sudo apt update docker pull ubuntu:18.04 切换 Shell 到 Ubuntu 18.04&#xff0c;输入以下命令&#xff1a; docker container run -p 8000:3000 -it ubuntu:18.04 /bin/bash -p 参数&#xff1a;容器的…

初学HTML:采用CSS绘制一幅夏天的图

下面代码使用了HTML和CSS来绘制一幅炎炎夏日吃西瓜的画面。其中&#xff0c;使用了伪元素和阴影等技巧来实现部分效果。 <!DOCTYPE html> <html> <head><title>炎炎夏日吃西瓜</title><style>body {background-color: #add8e6; /* 背景颜…

[UE4][C++]调整分屏模式下(本地多玩家)视口的显示位置和区域

一、分屏模式设置 在UE4中&#xff0c;多个玩家共用一个显示器就可以启用分屏模式&#xff0c;按玩家人数&#xff08;最大四人&#xff09;将屏幕均匀分割&#xff0c;显示不同玩家的视角&#xff0c;开发者可以在编辑器里设置分割类型&#xff08;水平或者垂直&#xff09;&a…

Redis如何实现排行榜?

今天给大家简单聊聊 Redis Sorted Set 数据类型底层的实现原理和游戏排行榜实战。特别简单&#xff0c;一点也不深入&#xff0c;也就 7 张图&#xff0c;粉丝可放心食用&#xff0c;哈哈哈哈哈~~~~。 1. 是什么 Sorted Sets 与 Sets 类似&#xff0c;是一种集合类型&#xff…

分治法 Divide and Conquer

1.分治法 分治法&#xff08;Divide and Conquer&#xff09;是一种常见的算法设计思想&#xff0c;它将一个大问题分解成若干个子问题&#xff0c;递归地解决每个子问题&#xff0c;最后将子问题的解合并起来得到整个问题的解。分治法通常包含三个步骤&#xff1a; 1. Divid…

2023年7月第4周大模型荟萃

2023年7月第4周大模型荟萃 2023.7.31版权声明&#xff1a;本文为博主chszs的原创文章&#xff0c;未经博主允许不得转载。 1、Cerebras推出全球最强AI超算 AI芯片初创公司Cerebras Systems和总部位于阿联酋的技术控股集团G42于7月20日宣布&#xff0c;携手打造一个由互联的超…

Docker 阿里云容器镜像服务

阿里云-容器镜像服务ACR 将本地/服务器docker image&#xff08;镜像&#xff09;推送到 阿里云容器镜像服务仓库 1. 在容器镜像服务ACR中创建个人实例 2. 进入个人实例 > 命名空间 创建命名空间 3. 进入个人实例 > 镜像仓库 创建镜像仓库 4. 进入镜像仓库 > 基本信…

CHI中的error处理

Error Handling Error types 包含两种sub-packet级别的error, 和两种packe级别的error; Packet level error Data Error, DERR □ 访问的地址是正确的&#xff0c;但是访问的数据有错误&#xff1b;通常是在数据崩溃的时候使用&#xff0c;例如ECC&#xf…

汽车销售企业消费税,增值税高怎么合理解决?

《税筹顾问》专注于园区招商、企业税务筹划&#xff0c;合理合规助力企业节税&#xff01; 汽车行业一直处于炙手可热的阶段&#xff0c;这是因为个人或者家庭用车的需求在不断攀升&#xff0c;同时随着新能源的技术进一步应用到汽车领域&#xff0c;一度实现了汽车销量的翻倍。…

Java读取及生成pb文件并转换jsonString

Java读取及生成pb文件并转换jsonString 1. 效果图2. 原理2.1 Protocol Buffers是什么2.2 支持的语言2.3 根据.proto生成.java2.4 初始化及构建pb&#xff0c;读取&#xff0c;转jsonString 3. 源码3.1 address.proto3.2 PbParseUtil.java 参考 读取pb及生成pb文件pb文件转换jso…

【Unity细节】关于NotImplementedException: The method or operation is not implemented

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐关于NotImplementedException: The method or operation is not implemented.⭐…

中药配方煎药-亿发智能中药汤剂煎煮系统,智慧中药房的数字化升级

随着中药的普及&#xff0c;在治病、养生等方面都发挥这积极作用&#xff0c;但中药煎煮过程繁琐&#xff0c;如果有所差错将会影响药品的药性。为了满足当今用户对中药的需求&#xff0c;增强生产效率和业务水平&#xff0c;亿发中药煎配智能管理系统应运而生&#xff0c;为用…

机器学习深度学习——多层感知机的从零开始实现

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——多层感知机 &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章对你们有所帮助 为…

Linux Day03

一、基础命令(在Linux Day02基础上补充) 1.10 find find 搜索路径 -name 文件名 按文件名字搜索 find 搜索路径 -cmin -n 搜索过去n分钟内修改的文件 find 搜索路径 -ctime -n搜索过去n分钟内修改的文件 1&#xff09;按文件名字 2&#xff09;按时间 1.11 grep 在文件中过…

【Ajax】笔记-同源策略

同源策略(Same-Origin Policy)&#xff0c;是浏览器的一种安全策略 同源&#xff08;即url相同&#xff09;&#xff1a;协议、域名、端口号 必须完全相同。&#xff08;请求是来自同一个服务&#xff09; 跨域&#xff1a;违背了同源策略&#xff0c;即跨域。 ajax请求是遵循…

软件测试面试题——接口自动化测试怎么做?

面试过程中&#xff0c;也问了该问题&#xff0c;以下是自己的回答&#xff1a; 接口自动化测试&#xff0c;之前做过&#xff0c;第一个版本是用jmeter 做的&#xff0c;1 主要是将P0级别的功能接口梳理出来&#xff0c;根据业务流抓包获取相关接口&#xff0c;并在jmeter中跑…

BUU CODE REVIEW 1

BUU CODE REVIEW 1 考点&#xff1a;PHP变量引用 源码直接给了 <?phphighlight_file(__FILE__);class BUU {public $correct "";public $input "";public function __destruct() {try {$this->correct base64_encode(uniqid());if($this->c…

回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测

回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实…

git stash clear清空本地暂存代码

git stash clear清空本地暂存代码 git stash 或者 git stash list 查看本地暂存的代码。 清除本地暂存的代码修改&#xff1a; git stash clear git回退代码仓库版本_git回退到之前的版本会影响本地代码嘛_zhangphil的博客-CSDN博客git回退代码版本_git回退到之前的版本会影…

没有软件测试经验,怎样面试测试工作?

纸上得来终觉浅&#xff0c;所有的面试经验都是要自己去体验&#xff0c;他人说来的都是他人的经验。 同样&#xff0c;每个公司&#xff0c;面对的面试官都会有不同的问题&#xff0c;当然这些问题可能会大同小异&#xff0c;但是也需要自己总结得出&#xff0c;这样的经验不…