linux内核链表应用--笔记

2023-05-16

Windows 应用linux内核链表

一、从网上现在linux kernel代码

linux内核版本有2种: 稳定版(次版本为偶数),开发版(次版本为奇数)
版本号: 主版本.次版本.释出版本-修改版本

内核下载连接网站:https://www.kernel.org/

下载内核版本:4.19.144
压缩文件大小:98.64MB

内核代码查看使用软件:Source Insight 4.0
Winddow软件平台:VS2019

二、关键文件

要进行移植的文件路径:

/linux-4.19.144/include/list.h

list.h文件里面定义了几个头文件,虽然这些定义的文件于list.h什么关系还不清楚,但可以一个一个清除跟他们之间的关系。换句话说,要从这些定义头文件里面复制相关代码出来,并加以修改。

#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/poison.h>
#include <linux/const.h>
#include <linux/kernel.h>

三、修改list.h头文件

1、/include/linux/types.h文件中找到有关链表的相关定义,代码拷贝下来

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

struct hlist_head {
    struct hlist_node* first;
};

struct hlist_node {
    struct hlist_node* next, ** pprev;
};

2、list.h中不需要调试链表,所以删除了预编译定义 #ifdef CONFIG_DEBUG_LIST#else 里面相关代码,只保留了 #else#endif 里面代码。

3、如果用C++语言编写,new会成为关键字,修改成newStruct

4、list.h中的宏定义WRITE_ONCE它的定义路径在

/tool/virtio/linux/compiler.h

5、进行第一次编译。。。发生了未定义NULL,在此出引用Windows.h头文件,用这个头文件的原因是我在Windows10平台下写的代码,应当遵循这个平台下的文件代码(有兼容作用)。

它里面是这样定义,当然也可以自己手动这样定义NULL,也可以添加头文件stdio.h这样不用声明这个NULL

#define NULL 0

6、第二次编译还是出现了大量的报错问题,一共三种报错,如下。


| 严重性| 代码|说明| 项目| 文件|行|禁止显示状态
| 错误 | C3861 |“typeof”: 找不到标识符 | list | E:\VS\list\list.h | 53 |
| 警告 | C4197| “volatile int”: 忽略强制转换中的顶级 volatile 变量 | list |E:\VS\list\list.h| 53|
| 错误(活动) | E0260 | 缺少显式类型(假定“int”) | list |E:\VS\list\list.h| 53|


主要还是复制过来的代码出现问题,慢慢分解这个代码修改前

#define WRITE_ONCE(var, val) \
	(*((volatile typeof(val) *)(&(var))) = (val))

#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var))))

C++不支持typeof() 这个东西,没办法获取获取变量类型,比如typeof(val),如果传入是无符号字节,那么它就会等效成unsigned char,为了解决不兼容这个问题,我们使用C11标准的 delctype() 来获取就可以了。

代码修改后

#define WRITE_ONCE(var, val) \
	(*((volatile decltype(val) *)(&(var))) = (val))

#define READ_ONCE(var) (*((volatile decltype(var) *)(&(var))))

7、C++编译器不支持 ({ }) 形式 ,这个要修改 , 然后为防止重复offsetof重复用宏定义,offsetof改为offsetof2;
代码修改后:

#define offsetof2(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) \
	(type *)( (char *)(ptr) - offsetof2(type,member))

四、移植完成后应用测试代码验证

#include "list.h" //移植后头文件名称
#include <iostream>

using namespace std;

struct student
{
	char name[60]; //学生名字
	int id;	//学生id号
	struct list_head list;//链表
};

int main(void)
{
	struct student *q;
	struct student *p;
	
	struct student A = { "Jack" ,1, LIST_HEAD_INIT(A.list) };//初始化变量
	struct student B = { "Pink" ,2, LIST_HEAD_INIT(B.list) };//初始化变量

	list_add(&B.list, &A.list);//添加到链表中

	//通过子变量获取父变量的地址
	q = container_of(&A.list, struct student , list);

	//查看q指向的下一个成员变量获取父变量的地址
	p = container_of(q->list.next, struct student , list);
	cout<<"name: "<<p->name<<endl;
	cout <<"id :"<< p->id << endl;

	//查看q指向的下一个的下一个成员变量获取父变量的地址
	p = container_of(q->list.next->next, struct student, list);
	cout << "name: " << p->name << endl;
	cout << "id :" << p->id << endl;

	//查看q指向的下一个的下一个的下一个成员变量获取父变量的地址
	p = container_of(q->list.next->next->next, struct student, list);
	cout << "name: " << p->name << endl;
	cout << "id :" << p->id << endl;

	return 0;
}

上面代码运行效果如下图所示。
在这里插入图片描述

Linux平台上应用linux内核链表

一、代码示例

下面代码也是在内核中参考应用得的

#include "list.hpp" //移植后头文件名称
#include <stdlib.h>
#include <stdio.h>

struct student
{
	int id;	//学生id号
	struct list_head list;//链表
};

int main(void)
{
	struct student *p,*t;
	struct student list_test;

	list_test.id = 333;
	t = &list_test;

	//初始化首个数据
	INIT_LIST_HEAD(&t->list);
	//列表是否为空?
	printf("队列是否为空?:%u\n",list_empty(&t->list));
	//生成10个学生ID
	for (int i = 0; i < 10; i++)
    {
        p = (struct student *)malloc(sizeof(struct student));
        INIT_LIST_HEAD(&p->list);
		//赋值一个ID
        p->id = i;
		//将数据添加到列表后面
        list_add_tail(&p->list, &list_test.list);
    }
    
	//列表是否为空?
	printf("队列是否为空?:%u\n",list_empty(&t->list));
	//遍历所有数据
	printf("list_for_each_entry :\n");
    list_for_each_entry(p, &t->list, list) {
        printf("%d\n",p->id);
    }

	//倒序遍历所有数据
	printf("list_for_each_entry_reverse :\n");
    list_for_each_entry_reverse(p, &t->list, list)
    {
        printf("%d\n",p->id);
    }

	struct student *a,*n;
	//删除所有数据,并释放内存空间
	list_for_each_entry_safe(a, n, &t->list, list) {
		printf("a:%d\n",a->id);
		printf("n:%d\n",n->id);
		list_del(&a->list);
		free(a);
	}

    return 0;
}

运行效果如下:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux内核链表应用--笔记 的相关文章

随机推荐

  • 本地项目上传至git码云步骤

    1 首先在本地配置好Git相关设置 2 在码云上新建一个仓库 xff0c 如图所示 xff0c 可以得到仓库地址 2 在本地需要上传的项目文件夹下鼠标右键选择git bash here xff0c 弹出dos窗口 3 第一步在窗口输入 gi
  • linux 服务器之间文件互传相关命令

    使用scp将一个Linux系统中的文件或文件夹复制到另一台Linux服务器上 一 复制文件 xff1a xff08 1 xff09 将本地文件拷贝到远程 scp 本地文件路径 用户名 64 远程计算机IP或者计算机名称 远程路径 把本地19
  • 【manjaro安装最新的搜狗输入法】2022年1月4号有效测试

    大多数教程都是如下安装 xff1a sudo pacman S fcitx sogoupinyin 但是我的pacman源是没有这个包的 查看yaourt是否有此包 xff1a 21 55 29 steed yaourt Ss fcitx
  • 52单片机设计时钟(串口控制)

    实现目标 单片机时钟正常工作 xff0c 数码管显示时分秒 电脑和单片机串行通信 xff0c 通过电脑串口助手 xff0c 任意修改设置单片机的时钟值 实现的流程框图 运用到的原理有 定时器 计数器 定时器 计数器由高8位和低8位两个寄存器
  • 照片修复-使用Bringing-Old-Photos-Back-to-Life

    项目地址 github项目地址 xff1a https github com microsoft Bringing Old Photos Back to Life 环境搭建 1 下载Bringing Old Photos Back to L
  • cephadm部署分布式ceph存储

    文章目录 一 集群规划系统优化添加yum源挂载本地yum源添加ceph网络yum源添加kernel网络yum源添加docker网络yum源 升级内核部署docker部署时间同步安装ceph引导一个新集群RBD块存储osd 操作打标签监控器调
  • OCR入门教程系列(二):OCR技术发展

    作者简介 CSDN 阿里云人工智能领域博客专家 新星计划计算机视觉导师 百度飞桨PPDE 专注大数据与AI知识分享 公众号 GoAI的学习小屋 免费分享书籍 简历 导图等 更有交流群分享宝藏资料 关注公众号回复 加群 或 链接 加群 专栏推
  • 利用CSS浮动制作一个简易导航栏

    初学CSS 利用CSS浮动和无序列表制作一个简易导航栏 xff1a lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8
  • ERROR Error: Cannot find module ‘vue-loader-v16/package.json‘ vue3.0安装时的错误

    vue3 0 出来一段时间了 xff0c 一直没机会学 xff0c 现在按照网上的教程安装时居然有报错 xff01 我的解决是 直接把项目里面的node modules和package lock json文件删除了 xff0c 然后在重新执
  • php 树形菜单数据获取

    php 树形菜单数据获取 public function generateTree data condition 61 array if empty condition foreach data as k 61 gt v if in arr
  • go语言编译前端静态文件到可执行文件 -statik

    statik 安装 go get github com rakyll statik statik 使用 1 把安装好的包 里面的 statik go 文件编译好 然后运行 2 编译好的statik go文件 src 61 你的静态文件路径
  • goLand全局修改时区

    两种方法 第一种 xff1a loc 61 time FixedZone 34 UTC 34 8 3600 time Local 61 loc 第二种 loc err 61 time LoadLocation 34 America Atka
  • python之Pyperclip模块

    python之Pyperclip模块 下面介绍一下 xff0c python中的Pyperclip模块 xff0c 它的简单又实用 xff0c 主要用法就2点 xff1a 1 用于复制剪贴板里的内容 2 向剪贴板写入内容 一 Pypercl
  • 利用栈判断一个字符串是否是回文

    利用栈判断一个字符串是否是回文 问题描述 编写一个程序 xff0c 判断一个字符串是否为回文 xff08 顺读和倒读都一样的字符串称为回文 xff09 输入形式 长度小于100的任意字符串 输出形式 如果输入字符串是回文 xff0c 则输出
  • Java把String转换成Date类型(Date转换成String类型)

    1 String转换成Date类型 span class token class name SimpleDateFormat span ft span class token operator 61 span span class toke
  • 微信小程序开发自学笔记 —— 七、性能优化

    性能优化 启动 在小程序启动时 xff0c 微信会为小程序展示一个固定的启动界面 xff0c 界面内包含小程序的图标 名称和加载提示图标 此时 xff0c 微信会在背后完成几项工作 xff1a 下载小程序代码包 加载小程序代码包 初始化小程
  • Error: failed to unmarshal json. invalid character “*”looking for beginning of value解决方案

    IPFS config时出现 Error failed to unmarshal json invalid character looking for beginning of value 在Win10 命令行执行ipfs config命令
  • Jsp的四种作用域范围

    首先要声明一点 xff0c 所谓 34 作用域 34 就是 34 信息共享的范围 34 xff0c 也就是说一个信息能够在多大的范围内有效 JSP的四种范围 xff0c 分别为page request session application
  • go 调用shell命令 两种方式(有无返回值)

    阻塞方式 需要执行结果 适用于执行普通非阻塞shell命令 xff0c 且需要shell标准输出的需要对shell标准输出的逐行实时进行处理的 非阻塞方式 不需要执行结果 官网的标准中文库 阻塞方式 需要执行结果 主要用于执行shell命令
  • linux内核链表应用--笔记

    Windows 应用linux内核链表 一 从网上现在linux kernel代码 linux内核版本有2种 稳定版 次版本为偶数 xff0c 开发版 次版本为奇数 版本号 主版本 次版本 释出版本 修改版本 内核下载连接网站 xff1a