Linux设备模型(十一) - platform设备

一,platform device概述

在Linux2.6以后的设备驱动模型中,需关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,

会寻找与之匹配的驱动;相反的,在系统每注册一个设备的时候,会寻找与之匹配的设备,而匹配由总线完成。

一个现实的Linux设备和驱动通常都需要挂接在一种总线上,而对于本身依附于PCI、USB、I2C、SPI等的设备而言,这自然不是问题,

但是在嵌入式系统里面,在SoC系统中集成的独立外设控制器、挂接在SoC内存空间的外设等却不依附于此类总线。基于这一背景,Linux

发明了一种虚拟总线,称为platform总线,相应的设备称为platform_device,而驱动称为platform_driver。

所谓的platform_device并不是与字符设备、块设备和网络设备并存的概念,而是linux系统提供的一种附加手段,例如,我们通常把在

SoC内部集成的I2C、RTC、LCD、看门狗等控制器都归纳为platform_device,而他们本身就是字符设备。这些设备有一个基本的特征:可以通过CPU bus直接寻址(例如在嵌入式系统常见的“寄存器”)。

二,platform模块的软件架构

内核中Platform设备有关的实现位于include/linux/platform_device.h和drivers/base/platform.c两个文件中,它的软件架构如下:

由图片可知,Platform设备在内核中的实现主要包括三个部分:

Platform Bus,基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备;

Platform Device,基于底层device模块,抽象出Platform Device,用于表示Platform设备;

Platform Driver,基于底层device_driver模块,抽象出Platform Driver,用于驱动Platform设备。

其中Platform Device和Platform Driver会给其它Driver提供封装好的API,具体可参考后面的描述。

三,platform bus/platform device/platform driver结构体

1,platform_driver

// msm_kernel\include\linux\platform_device.h
struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table; /* 另外这里有一个id_table的指针,该指针和of_match_table、acpi_match_table的功能类似:提供其它方式的设备probe */bool prevent_deferred_probe;ANDROID_KABI_RESERVE(1);
};

2,platform_device

// msm_kernel\include\linux\platform_device.h
struct platform_device {const char    *name; /* 设备的名称,和struct device结构中的init_name意义相同。实际上,该名称在设备注册时,会拷贝到dev.init_name中 */int        id; /* 用于标识该设备的ID。内核允许存在多个名称相同的设备。而设备驱动的probe,依赖于名称,Linux采取的策略是:在bus的设备链表中查找device,和对应的device_driver比对name,如果相同,则查看该设备是否已经绑定了driver(查看其dev->driver指针是否为空),如果已绑定,则不会执行probe动作,如果没有绑定,则以该device的指针为参数,调用driver的probe接口。
因此,在driver的probe接口中,通过判断设备的ID,可以知道此次驱动的设备是哪个*/bool        id_auto; /* 指示在注册设备时,是否自动赋予ID值 */struct device    dev; /* 真正的设备(Platform设备只是一个特殊的设备,因此其核心逻辑还是由底层的模块实现) */u64        platform_dma_mask;struct device_dma_parameters dma_parms;u32        num_resources;struct resource    *resource; /* 该设备的资源描述,由struct resource(include/linux/ioport.h)结构抽象 */const struct platform_device_id    *id_entry;char *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata    archdata;ANDROID_KABI_RESERVE(1);ANDROID_KABI_RESERVE(2);
};

3,platform bus

// msm_kernel\drivers\base\platform.c
struct bus_type platform_bus_type = {.name        = "platform",.dev_groups    = platform_dev_groups,.match        = platform_match,.uevent        = platform_uevent,.dma_configure    = platform_dma_configure,.pm        = &platform_dev_pm_ops,
};
EXPORT_SYMBOL_GPL(platform_bus_type);

四,platform bus/platform device/platform driver注册

1,platform bus注册

struct device platform_bus = {.init_name    = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);int __init platform_bus_init(void)
{int error;early_platform_cleanup(); /* 清除所有和Early device/driver相关的代码。因为执行到这里的时候,证明系统已经完成了Early阶段的启动,转而进行正常的设备初始化、启动操作,所以不再需要Early Platform相关的东西。 */error = device_register(&platform_bus); /* 在sysfs中创建/sys/devices/platform目录,所有的platform设备都会包含在此目录下 */if (error) {put_device(&platform_bus);return error;}error =  bus_register(&platform_bus_type); /* 在sysfs中创建/sys/bus/platform目录并在此目录中创建如下attributes和devices目录,drivers目录 *//*lynkco:/sys/bus/platform # lsdevices  drivers  drivers_autoprobe  drivers_probe  uevent*/if (error)device_unregister(&platform_bus);of_platform_register_reconfig_notifier();return error;
}

2,platform device注册

platform_device_register - add a platform device to device hierarchy// msm_kernel\drivers\base\platform.c
platform_device_register(struct platform_device *pdev)
----device_initialize(&pdev->dev);
----platform_device_add(pdev);
--------pdev->dev.parent = &platform_bus; //该设备的sysfs目录/sys/devices/platform/xxx_device
--------pdev->dev.bus = &platform_bus_type; //该设备的bus type定义为platform_bus_type
--------dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id); //对于多个同名的设备,可以使用ID区分,在这里将实际名称修改为“name.id”的形式
--------insert_resource(p, r); /* 调用resource模块的insert_resource接口,将该设备需要使用的resource统一管理起来(我们知道,在这之前,只是声明了本设备需要使用哪些resource,但resource模块并不知情,也就无从管理,因此需要告知)。 */
--------device_add(&pdev->dev); // 将内嵌的struct device变量添加到内核中......

3,platform driver注册

platform_driver_register - register a driver for platform-level devices// msm_kernel\drivers\base\platform.c
platform_driver_register(drv)
----__platform_driver_register(drv, THIS_MODULE)
--------drv->driver.bus = &platform_bus_type; //该driver的bus type设置为platform_bus_type
------------drv->driver.probe = platform_drv_probe; /* 如果该platform driver提供了probe、remove、shutdown等回调函数,将该它内嵌的struct driver变量的probe、remove、shutdown等指针,设置为platform模块提供函数,包括platform_drv_probe、platform_drv_remove和platform_drv_shutdown。因为probe等动作会从struct driver变量开始,经过platform_drv_xxx等接口的转接就可以到达platform diver自身的回调函数中。*/
------------drv->driver.remove = platform_drv_remove;
------------drv->driver.shutdown = platform_drv_shutdown;
--------driver_register(&drv->driver); //将内嵌的struct driver变量添加到内核中......

五,platform device/platform driver提供的API

1,platform driver提供的API

extern int platform_driver_register(struct platform_driver *);
extern void platform_driver_unregister(struct platform_driver *); //platform driver的注册、注销接口extern int platform_driver_probe(struct platform_driver *driver,int (*probe)(struct platform_device *)); //主动执行probe动作static inline void *platform_get_drvdata(const struct platform_device *pdev);
static inline void platform_set_drvdata(struct platform_device *pdev,void *data); //设置或者获取driver保存在device变量中的私有数据

2,platform device提供的API

extern int platform_device_register(struct platform_device *);
extern void platform_device_unregister(struct platform_device *); //Platform设备的注册/注销接口,和底层的device_register等接口类似extern struct resource *platform_get_resource(struct platform_device *,unsigned int, unsigned int);
extern int platform_get_irq(struct platform_device *, unsigned int);
extern struct resource *platform_get_resource_byname(struct platform_device *,unsigned int,const char *);
extern int platform_get_irq_byname(struct platform_device *, const char *); //通过这些接口,可以获取platform_device变量中的resource信息,以及直接获取IRQ的number等等extern int platform_device_add_resources(struct platform_device *pdev,const struct resource *res,unsigned int num); //向platform device中增加资源描述extern int platform_device_add_data(struct platform_device *pdev,const void *data, size_t size); //向platform device中添加自定义的数据(保存在pdev->dev.platform_data指针中)

六,platform device resource/platform data的定义与获取

1,struct resource结构体介绍

在platform device结构体的定义中关于device resource的定义如下

    u32        num_resources;struct resource    *resource;

它们描述了platform_device的资源,资源本身由resource结构体描述

/*
* Resources are tree-like, allowing
* nesting etc..
*/
struct resource {resource_size_t start;resource_size_t end;const char *name;unsigned long flags;unsigned long desc;struct resource *parent, *sibling, *child;ANDROID_KABI_RESERVE(1);ANDROID_KABI_RESERVE(2);ANDROID_KABI_RESERVE(3);ANDROID_KABI_RESERVE(4);
};

我们通常关心start、end和flags这3个字段,它们分别标明了资源的开始值、结束值和类型,flags可以为IORESOURCE_IO、IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA等。

start、end的含义会随着flags而变更,如当flags为IORESOURCE_MEM时,start、end分别表示该platform_device占据的内存的开始地址和结束地址;

当flags为IORESOURCE_IRQ时,start、end分别表示该platform_device使用的中断号的开始值和结束值,如果只使用了一个中断号,开始值和结束值相同。

对于同种类型的资源而言,可以有多份,例如说某设备占据了两个内存区域,则可以定义两个IORESOURCE_MEM资源。

系统中所有的platform_device,都可以在/sys/devices/platform/路径下查看。另外,系统中所有的platform_device,有来自设备树的,也有来自.c文件中注册的。那么,我们怎么知道哪些platform_device是来自设备树,哪些是来自.c文件中注册的?

可以查看该platform_device的相关目录下,是否有of_node,如果有of_node,那么这个platform_device就来自于设备树;否则,来自.c文件。

2,来自.c文件中注册的platform_device

2.1 example
// msm_kernel\arch\arm\mach-ep93xx\core.cstatic struct usb_ohci_pdata ep93xx_ohci_pdata = {.power_on    = ep93xx_ohci_power_on,.power_off    = ep93xx_ohci_power_off,.power_suspend    = ep93xx_ohci_power_off,
};static struct resource ep93xx_ohci_resources[] = {DEFINE_RES_MEM(EP93XX_USB_PHYS_BASE, 0x1000),DEFINE_RES_IRQ(IRQ_EP93XX_USB),
};static struct platform_device ep93xx_ohci_device = {.name        = "ohci-platform",.id        = -1,.num_resources    = ARRAY_SIZE(ep93xx_ohci_resources),.resource    = ep93xx_ohci_resources,.dev        = {.dma_mask        = &ep93xx_ohci_dma_mask,.coherent_dma_mask    = DMA_BIT_MASK(32),.platform_data        = &ep93xx_ohci_pdata,},
};
platform_device_register(&ep93xx_ohci_device);

设备除了可以在BSP中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断、内存等标准资源以外,还可能有一些配置信息,而这些配置信息也依赖于板,不适宜直接放置在设备驱动上。因此platform也提供了platform_data的支持,platform_data的形式是由每个驱动自定义的,如对于usb ohci设备而言,platform_data为一个usb_ohci_pdata结构体,完成定义后将可以将PM operation相关的接口信息放入platform_data中。

在usb ohci驱动msm-kernel/drivers/usb/host/ohci-platform.c的probe()函数中,通过如下方式就拿到了platform_data:

static int ohci_platform_probe(struct platform_device *dev)    
{struct usb_hcd *hcd;struct resource *res_mem;struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);struct ohci_platform_priv *priv;... ...
}
2.2 memory resource资源的定义
#define DEFINE_RES_MEM(_start, _size)                    \DEFINE_RES_MEM_NAMED((_start), (_size), NULL)#define DEFINE_RES_MEM_NAMED(_start, _size, _name)            \DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_MEM)/* helpers to define resources */
#define DEFINE_RES_NAMED(_start, _size, _name, _flags)            \{                                \.start = (_start),                    \.end = (_start) + (_size) - 1,                \.name = (_name),                    \.flags = (_flags),                    \.desc = IORES_DESC_NONE,                \}
2.3 irq resource资源的定义
#define DEFINE_RES_IRQ(_irq)                        \DEFINE_RES_IRQ_NAMED((_irq), NULL)#define DEFINE_RES_IRQ_NAMED(_irq, _name)                \DEFINE_RES_NAMED((_irq), 1, (_name), IORESOURCE_IRQ)
2.4 IO resources flags
/*
* IO resources have these defined flags.
*
* PCI devices expose these flags to userspace in the "resource" sysfs file,
* so don't move them.
*/
#define IORESOURCE_BITS        0x000000ff    /* Bus-specific bits */#define IORESOURCE_TYPE_BITS    0x00001f00    /* Resource type */
#define IORESOURCE_IO        0x00000100    /* PCI/ISA I/O ports */
#define IORESOURCE_MEM        0x00000200
#define IORESOURCE_REG        0x00000300    /* Register offsets */
#define IORESOURCE_IRQ        0x00000400
#define IORESOURCE_DMA        0x00000800
#define IORESOURCE_BUS        0x00001000

3,来自设备树的platform_device

在Linux内核启动时,内核通过 of_platform_populate() 函数,将dts中的device node创建成platform device。为后续和各类驱动的platform driver匹配做准备。

of_platform_device_create_pdata
----of_device_alloc
--------of_address_to_resource(np, num_reg, &temp_res)
--------num_irq = of_irq_count(np);
--------dev->num_resources = num_reg + num_irq;
--------dev->resource = res;
--------of_address_to_resource(np, i, res);
--------of_irq_to_resource_table(np, res, num_irq); //将dts中的address和irq等信息转化到resource结构体中
--------dev->dev.bus = &platform_bus_type;
----dev->dev.platform_data = platform_data;
----of_device_add(dev)
--------device_add(&ofdev->dev);

具体解析转化过程会在后续的dts章节中详细分析。

4,get resource API实现及使用

4.1 get resource API实现

platform_get_resource_byname:

/**
* platform_get_resource_byname - get a resource for a device by name
* @dev: platform device
* @type: resource type
* @name: resource name
*/
struct resource *platform_get_resource_byname(struct platform_device *dev,unsigned int type,const char *name)
{u32 i;for (i = 0; i < dev->num_resources; i++) {struct resource *r = &dev->resource[i];if (unlikely(!r->name))continue;if (type == resource_type(r) && !strcmp(r->name, name)) //匹配type和namereturn r;}return NULL;
}
EXPORT_SYMBOL_GPL(platform_get_resource_byname);

platform_get_resource:

/**
* platform_get_resource - get a resource for a device
* @dev: platform device
* @type: resource type
* @num: resource index
*
* Return: a pointer to the resource or NULL on failure.
*/
struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num)
{u32 i;for (i = 0; i < dev->num_resources; i++) {struct resource *r = &dev->resource[i];if (type == resource_type(r) && num-- == 0) //匹配type和indexreturn r;}return NULL;
}
EXPORT_SYMBOL_GPL(platform_get_resource);
4.2 get resource API使用示例

get memory resource使用示例:

struct resource *res;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");return -ENODEV;
}adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,resource_size(res));
if (!adata->acp3x_base)return -ENOMEM;

get irq resource 使用示例:

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");return -ENODEV;
}
adata->i2s_irq = res->start;status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,irqflags, "ACP3x_I2S_IRQ", adata);
if (status) {dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n");return -ENODEV;
}

get resource by name 使用示例:

struct resource *r;/* card: irq assigned to the card itself. */
r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
sock->card_irq = r ? r->start : 0;/* stschg: irq which trigger on card status change (optional) */
r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
sock->stschg_irq = r ? r->start : -1;/* 36bit PCMCIA Memory area address */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
if (!r) {printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n",sock->nr);goto out0;
}
sock->phys_mem = r->start;

由以上分析可知,在设备驱动中引入platform的概念至少有如下好处:

1)使得设备被挂接在一个总线上,符合Linux2.6以后内核的设备模型。其结果是使配套的sysfs节点、设备电源管理都成为可能。

2)隔离BSP和驱动。在BSP中定义platform设备和设备使用的资源、设备的具体配置信息,而在驱动中,只需要通过通用API去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。

3)让一个驱动支持多个设备实例。

参考链接:

Linux设备模型(8)_platform设备

dts展开为platform_device结构过程分析-腾讯云开发者社区-腾讯云

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可让照片人物“开口说话”阿里图生视频模型EMO,高启强普法

3 月 1 日消息&#xff0c;阿里巴巴研究团队近日发布了一款名为“EMO&#xff08;Emote Portrait Alive&#xff09;”的 AI 框架&#xff0c;该框架号称可以用于“对口型”&#xff0c;只需要输入人物照片及音频&#xff0c;模型就能够让照片中的人物开口说出相关音频&#xf…

PDN分析及应用系列二-简单5V电源分配-Altium Designer仿真分析-AD

PDN分析及应用系列二 —— 案例1:简单5V电源分配 预模拟DC网络识别 当最初为PCB设计打开PDN分析仪时,它将尝试根据公共电源网络命名法从设计中识别所有直流电源网络。 正确的DC网络识别对于获得最准确的模拟结果非常重要。 在示例项目中已经识别出主DC网络以简化该过程。 …

Vulnhub靶机:Bellatrix

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.4&#xff09; 靶机&#xff1a;Bellatrix&#xff08;10.0.2.9&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/entry/hogwa…

网络学习:MPLS技术基础知识

目录 一、MPLS技术产生背景 二、MPLS网络组成&#xff08;基本概念&#xff09; 1、MPLS技术简介&#xff1a;Multiprotocol Lable Switching&#xff0c;多协议标签交换技术 2、MPLS网络组成 三、MPLS的优势 四、MPLS的实际应用 一、MPLS技术产生背景 1、IP采用最长掩码…

Power BI vs Superset BI 调研报告

调研结论 SupersetPower BI价格开源①. Power BI Pro 每人 $10/月($120/年/人) ②. Power BI Premium 每人 $20/月($240/年/人) ③. Power BI Embedded:4C10G $11W/年 权限基于角色的访问控制,支持细粒度的访问: 表级别、库级别、图表级别,看板级别,用户级别 基于角色…

【推荐】免费AI论文写作神器-「智元兔 AI」

还在为写论文焦虑&#xff1f;免费AI写作大师来帮你三步搞定&#xff01; 智元兔AI是ChatGPT的人工智能助手&#xff0c;并且具有出色的论文写作能力。它能够根据用户提供的题目或要求&#xff0c;自动生成高质量的论文。 不论是论文、毕业论文、散文、科普文章、新闻稿件&…

#WEB前端(浮动与定位)

1.实验&#xff1a; 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; float、position 没有应用浮动前 应用左浮动和右浮动后 应用定位 4.代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><me…

pyqt5怎么返回错误信息给页面(警告窗口)

在软件设计中&#xff0c;我们可能会遇到对异常的处理&#xff0c;有些异常是用户需要看到的&#xff0c;比如说&#xff0c;当我们登录出错的时候&#xff0c;后端需要给我们返回响应的错误信息&#xff0c;就像下图实现的这样。 类似这种效果&#xff0c;我们该如何实现&…

javaWebssh题库管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh题库管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Mye…

「MySQL」基本操作类型

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;数据库 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 数据库的操作 创建、显示数据库 使用 create 创建一个数据库 create database goods;然后可以用 show databases 来查看已经创建的数…

javaWebssh网上超市销售管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh网上超市销售管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCA…

指针深刻理解

指针深刻理解 看完鹏哥讲的c语言进阶视频后&#xff0c;又找来C语言深度剖析这本书仔细看了一遍&#xff0c;来进一步巩固和理解指针这个重点。 1&#xff1a;数组 如上图所示&#xff0c;当我们定义一个数组 a 时&#xff0c;编译器根据指定的元素个数和元素的类型分配确定大…

身份证识别系统(安卓)

设计内容与要求&#xff1a; 通过手机摄像头捕获身份证信息&#xff0c;将身份证上的姓名、性别、出生年月、身份证号码保存在数据库中。1&#xff09;所开发Apps软件至少需由3-5个以上功能性界面组成。要求&#xff1a;界面美观整洁、方便应用&#xff1b;可以使用Android原生…

JS 对象数组排序方法测试

输出 一.Array.prototype.sort() 1.默认排序 sort() sort() 方法就地对数组的元素进行排序&#xff0c;并返回对相同数组的引用。默认排序是将元素转换为字符串&#xff0c;然后按照它们的 UTF-16 码元值升序排序。 由于它取决于具体实现&#xff0c;因此无法保证排序的时…

数据可视化基础与应用-02-基于powerbi实现医院数据集的指标体系的仪表盘制作

总结 本系列是数据可视化基础与应用的第02篇&#xff0c;主要介绍基于powerbi实现医院数据集的指标体系的仪表盘制作。 数据集描述 医生数据集doctor 医生编号是唯一的&#xff0c;名称会存在重复 医疗项目数据projects 病例编号是唯一的&#xff0c;注意这个日期编号不是真…

面试时如何回答接口测试怎么进行

一、什么是接口测试 接口测试顾名思义就是对测试系统组件间接口的一种测试&#xff0c;接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 …

【C++ 07】string 类的常用接口介绍

文章目录 &#x1f308; Ⅰ string 类对象的常见构造函数&#x1f308; Ⅱ string 类对象的容量相关操作&#x1f308; Ⅲ string 类对象的访问及遍历1. 下标访问及遍历2. 正向迭代器访问3. 反向迭代器访问 &#x1f308; Ⅳ string 类对象的修改操作1. 插入字符或字符串2. 字符…

Vue前端的工作需求

加油&#xff0c;新时代打工人&#xff01; 需求&#xff1a; 实现带树形结构的表格&#xff0c;父数据显示新增下级&#xff0c;和父子都显示编辑。 技术&#xff1a; Vue3 Element Plus <template><div><el-table:data"tableData"style"width…

了解游戏中的数据同步

目录 数据同步 通过比较来看状态同步和帧同步 状态同步 帧同步 帧同步实现需要的条件 两者相比较 数据同步 在联机游戏中&#xff0c;我的操作和数据要同步给同一局游戏中其他所有玩家&#xff0c;其他玩家的操作和数据也会同步给我。这叫做数据同步&#xff0c;目前数据…

国产数据库概述

这是ren_dong的第33篇原创 1、什么是数据库&#xff1f; 1.1、基本概念 定义&#xff1a;数据库是 按照一定的数据结构组织、存储和管理数据的仓库。可视为电子化的文件柜&#xff0c;用户可以对文件中的数据进行新增、查询、更新、删除等操作。 作用&#xff1a;业务数据 存储…