汇编语言程序设计(二)之寄存器
系列文章
汇编语言程序设计(一)
寄存器
在学习汇编的过程中,我们经常需要操作寄存器,那么寄存器又是什么呢?它是用来干什么的?
它有什么分类?又该如何操作?…
你可能会有许多的问题,答案都会在本文中进行揭晓。
1 寄存器的概念
一个典型的CPU由运算器、控制器、寄存器等器件组成 ,这些器件靠内部总线相连,内部总线实现CPU,内部各个器件之间的联系,而CPU与外设(主板上的其他器件)之间的联系则由外部总线连接。
简单来说,在CPU中:
1):运算器进行信息处理;
2):寄存器进行信息存储;
3):控制器控制各种器件进行工作;
4):内部总线连接各种器件,在他们之间进行数据的传送;
下图为cpu组成:
从上述描述中我们可以看出寄存器可以用来存储指令和数据。对于一个汇编程序员来说,CPU的主要部件是寄存器。寄存器是CPU中程序可以用指令读写的器件。程序员通过改变各种寄存器中内容来实现对CPU的控制。不同的CPU,寄存器的个数、结构是不同的。8086CPU由14个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。这些寄存器有着不同的功能,在不同的场合扮演着不同的角色。后续的讲解中我们将逐渐接触到这些寄存器,这里我们就不一一介绍。
这里我们先介绍一些通用寄存器:AX、BX、CX、DX
8086CPU所有寄存器都是16位的,可以存放两个字节,上述4个寄存器通常用来存放一般性的数据,被称为通用寄存器。以AX为例,寄存器的逻辑结构如下图
一个16位寄存器可以存储一个16位的数据,例如如果AX中存储的是32这个数值,存放结果如下图所示:
而8086CPU为了兼容上一代CPU中的寄存器(上一代CPU中的寄存器位8位),上述这些寄存器又可以分为两个可独立使用的8位寄存器来用:AX可以分为AH、AL,同理,BX又可以分为BH、BL,CX可以分为CH、CL,DX可以分为DH、DL(H位high,L为low),以AX为例,它拆分成两个独立的8位寄存器表示如下:
AX的低8bits构成了AL寄存器,高8bit构成了AH寄存器,AH和AL都是可以独立使用的寄存器。
2 字的存储
我们应该听过字节的概念,1字节等于8比特位,那么字和字节又有什么关联呢?1个字等于2个字节。
比特记为bit,字节记为Byte,字记为word,所以有如下关系:
1Byte = 8bits,1word = 2Bytes = 16bits
而8086CPU出于兼容性的考虑,一次性可以处理两种尺寸的数据:字节以及字数据
一个寄存器可以存储一个字数据,例如数据2000,其二进制数值为:0000 0111 1101 0000,储存格式如下:
这样就是2000在寄存器中的存储格式(以AX为例),在AH中储存了它的高八位,AL存储了它的低八位。AH和AL中的数据可以看成一个整体是数值为2000,又可以看成是两个独立的数据,分别是7和208。上述是从寄存器出发,描述了一个16位数据在寄存器中的存储格式,而我们在使用汇编的过程中还会操作内存,那么在内存中一个字又可以用怎么样的格式体现呢?
我们要知道内存单元是字节单元也就是说一个字节单元对应一个内存单元,当我们要保存一个子数据时,我们应该用两个地址连续的内存单元来保存。数据的低字节存放在低地址单元中,高字节存放在高地址单元中,假设我们从0地址开始存放2000,情况如下:
我们用0、1两个内存单元存放数据2000(07D0H)。0、1两个单元用来储存一个字,这两个单元可以看成一个起始地址为0的字单元,对于这个字单元来说,0是低地址单元,1是高地址单元。07H被存放在高地址单元,而D0H被存放在低地址单元。同理,我们也可以把2,3看成一个字单元。
在这里有一个新的概念:字单元,用来描述一种用来存储字型数据的内存单元。
3 物理地址与段地址
CPU在访问内存单元之前,应该要给出内存单元的地址。所有的内存单元构成的存储的空间是一个一维的线性空间,每一个内存单元在这个空间中都有一个唯一的地址,我们称之为物理地址。
那么8086CPU又是如何形成这些物理地址的呢?
我们案例中的8086CPU是16位机,这种CPU具备如下特性:
1):一次最多可以处理16位的数据;
2):寄存器的最大宽度是16位;
3):寄存器和运算器之间的通路为16位;
也就是说,8086CPU内部一次性能处理的数据长度最大为16位。内存单元的地址在送上地址总线之前还需要经过寄存器进行处理,也就是说16位CPU,能一次性处理16位的地址。但是8086CPU的地址总线是20位,也就是说8086CPU可以传送20位地址,这与上述说法相悖,那这又是为什么呢?
8086CPU在内部有一个地址加法器可以将两个16位地址合成一个20位物理地址,示意图如下:
当CPU要操作内存时,内部有如下事件发生:
1):CPU中的相关部件提供了两个16位地址,一个称为段地址,一个称为偏移地址;
2):段地址和偏移地址经过内部总线送入地址加法器;
3):地址加法器将两个16位地址合成一个20位的物理地址;
4):地址加法器将20位的物理地址通过内部总线送入输入输出控制电路;
5):输入输出控制电路将20位地址送入地址总线
6):20位物理地址被地址总线送到存储器
地址加法器采用物理地址=段地址*16+偏移地址的方法来合成物理地址,这样一个16位机就可以访问20位地址,寻址能力也从64KB扩大成1MB。
例如CPU要访问地址为123C8H的内存单元,地址加法器的工作过程为:
4 CS和IP
在讲CS和IP之前,我们需要了解一个概念:段。
上节我们讲到“段地址”,那么段又是什么呢?段和段地址有什么关系呢?在中文中我们可以很好的理解段的含义:表示某个范围/区间,也就是说“段地址”我们可以理解为一段地址,更规范的说法是一块地址连续且起始地址为16倍数的存储单元定义为一个段。也就是说我们可以将内存进行分段处理,当然我们不要误解为内存本身就是一段一段的,这是一个错误的认知。内存本身是连续的,只不过8086CPU采用“物理地址=段地址*16+偏移地址”来产生物理地址,我们可以通过分段的方式来管理内存。
假设目前有两个段:10000H ~ 1007FH(段地址为1000H)、10080H ~ 100FFH,段地址为(1008H),两个段大小均为80H,其内存中分布示意如下:
这样我们在编程时就可以根据需要将一块地址连续的存储单元看成一个段,通过“物理地址=段地址*16+偏移地址”来定位段中的内存。注意:段地址一定是16的倍数,且段的最大长度为64KB。
从上述描述中我们已经知道了什么是段了,在前面的讲述中我们说段地址是由CPU中的相关部件提供,那么这个相关部件是哪个呢?在众多的寄存器中的有4个**段寄存器:**CS,DS,SS,ES。当CPU要访问内存时,由他们提供段地址。这里我们看一下CS。
CS和IP是8086CPU中最关键的两个寄存器。它们指示CPU当前要读取的指令的地址。CS称之为代码段寄存器,IP为指令指针寄存器。
在8086CPU中,任意时刻设CS中的值为M,IP中的值为N,则CPU将从M*16+N地址单元中取出一条指令并执行。也就是说,当前执行的指令在哪由CS和IP来决定。可以表示为CS:IP。下图为CPU通过CS、IP寄存器进行指令操作:
上图说明如下:
1):CS中内容为2000H,IP内容为0000H:说明物理地址为20000H
2):内存20000H~20009H内存单元中存放着可执行的机器码
3):内存20000H~20009H内存单元中存放的可执行的机器码对应的汇编指令如下:
地址:20000H~20002H 内容:B8 23 01 对应的汇编指令:mov ax,0123H
地址:20003H~20005H 内容:BB 03 00 对应的汇编指令:mov bx,0003H
地址:20006H~20007H 内容:89 D8 对应的汇编指令:mov ax,bx
地址:20008H~20009H 内容:01 D8 对应的汇编指令:add ax,bx
那么上述的状态下程序又是如何执行的呢?
1):CPU从CS:IP指向的存储单元中读取指令,读取的指令进入指令缓冲区;
2):IP=IP+所读取的指令的长度,从而指向下一条指令;
3):执行指令。重复1、2步。
注意:8086CPU在启动/复位启动之后,CS被设置为FFFFH,IP被设置为0000H,也就说,8086CPU在启动时执行的的第一条指令为FFFF0H指向单元中的指令。
5 DOS软件的安装及使用
关于DOS:磁盘操作系统(Disk Operating System),是早期个人计算机上的一类操作系统。从1981年MS-DOS1.0直到1995年MS-DOS 6.22的15年间,DOS作为微软公司在个人计算机上使用的一个操作系统载体,推出了多个版本。DOS在IBM PC 兼容机市场中占有举足轻重的地位。可以直接操纵管理硬盘的文件,以DOS的形式运行。
DOS家族包括MS-DOS、PC-DOS、DR-DOS、FreeDOS、NovellDOS、PTS-DOS、ROM-DOS、JM-OS等,其中以MS-DOS最为著名,最自由开放的则是Free-DOS。虽然这些系统常被简称为"DOS",但没有任何一个系统单纯以"DOS"命名。
DOSBOX软件下载:可以自己去网上下载
MASM软件包下载:可以自己去网上下载
关于DOS的安装:一路向下即可(对于安装位置选择自行浏览)
MASM安装:不需要安装直接解压即可(解压在你设置的虚拟C盘)
关于DOS的指令:(不做深入)
1. dir查看当前目录下文件和文件夹
2. cd进入特定目录cd code 进入当前目录下的code目录cd\ 切换到根目录cd.. 切换到上一级目录
3.md 建立特定文件夹md code 在当前目录下建立一个名字叫code的目录
4.rd 删除特定文件夹rd code 删除当前目录下的code文件夹
5.cls清除屏幕。清除屏幕上所有的显示内容。只留下当前的命令行。
6.exit推出当前命令解释程序并返回到系统
//其他指令大家可以自己了解,这里不做过多深入
程序的编译过程:
1.设置虚拟盘mount c D:\MASM //将D盘目录下的MASM的作为虚拟盘C盘
2.进入到设置到的C盘c:
3.在D:\MASM文件夹下新建一个1.asm直接在windows中创建即可
4.编译源文件masm 1.asm //---》这里会产生一个中间文件 1.obj
5.链接link 1.obj //---》这里会产生一个目标文件 1.exe
6.1.exe即为可执行程序,可以直接执行了(输入名字即可) 上述1-2步每次开启DOS时都要执行,这样比较麻烦,做如下处理就不需要开机时输入了: 打开DOSBOX的安装文件夹,找到DOSBox 0.74 Options,打开,在其末尾添加这两行mount c D:\MASMc:
设置DOS窗口大小:打开DOSBOX的安装文件夹,找到DOSBox 0.74 Options,打开,找到windowresolution以及output修改成如下windowresolution=1280x800output=opengl
程序的debug过程:
上述操作生成一个可执行程序之后,比如说1.exe
在DOS命令行输入:debug 1.exeR命令查看/修改CPU中寄存器的内容输入:r ax 回车会出来一个:在后面输入你想要改变的数据就可以改变ax中的内容,其它寄存器同理D命令查看内存中的内容d段地址:偏移地址 回车可以查看该物理地址制定的内存中的内容如:d1000:0000E命令改写内存中的内容e 段地址:偏移地址 要修改的内容如:e 1000:0000 0 1 2 3 4 5 6 7 U命令将内存中的机器指令翻译成汇编指令简单理解为查看源码 T命令执行一条机器指令单步执行程序 A命令以汇编指令的格式在内存中写入一条机器指令...quit 退出debug
6 段的分类
前面讲过,对于8086PC机,再编程时可以根据需要将一组内存单元定义为一个段。我们可以将长度为N(N<=64KB)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中,我们可以认为,这段内存是用来存储代码的,从而定义了一个代码段。比如:
mov ax,0000 ;(B8 00 00)
add ax,0123H ;(05 23 01)
mov bx,ax ;(8B D8)
jmp bx ;(FF E3)
上述代码长度为10个字节(括号里面的为每条指令对应的机器码)的指令,我们将它存放在 123B0H-123B9H 的一组内存单元中,我们就可以认为 123B0H-123B9H这段内存是用来存放代码的,是一个代码段,段地址为123BH,长度为10个字节。
虽然我们可以将上述代码设置在一个代码段内,但是这仅仅我们编程时的一种安排,CPU并不会因为这种安排,就自动的将我们定义的代码段中的指令当做指令来执行。CPU只认被CS:IP指向的内存单元中的内容为指令。所以,要让CPU执行我们设置为代码段中指令,我们需要改变CS:IP指向的内容,换而言之,需要将CS:IP指向123B0这个单元。也就是说需要设置CS=123BH,IP=0000H。在这里大家只要知道有代码段这个概念即可,不需要做太多过于深入的探讨。
我们可以假想这组数据可以存储在某块内存内,我们知道这块内存的地址,那么我们在使用时就可以通过内存地址找到这些数据了。我们参考上述代码段的概念,我们可以设置一个数据段,用来存储这组数据。同样的,对于数据段来说,这仍然是我们编程时的一种安排,再具体操作的时候,我们需要将DS寄存器存放数据段的段地址,当我们在使用数据的时候只需要给出偏移地址就可以了,例如如下程序:
(我们假设这个数据段的段地址为123B0H)
mov ax,123BH
mov ds,ax ;将123BH送入ds中,作为数据段的段地址 (这里不能直接 mov ds,123BH)
mov al,[0] ;这句话的含义是将123B0:0000H单元中的内容存入al中
在这里我们就可以好好的认识一下这几个段寄存器了:CS,DS,SS,ES
代码段寄存器(code segment):CS
存放当前正在运行的程序代码所在段的段基址,表示当前使用的指令代码可以从该段寄存器指定的存储器段中取得,相应的偏移地址则由**IP(指令指针寄存器)**提供;
数据段寄存器(data segment):DS
指出当前程序使用的数据所存放段的最低地址,即存放数据段的段地址;
栈段寄存器(stack segment):SS
指出当前堆栈的底部地址,即存放堆栈段的段基址。SS:SP指向栈顶单元。
附加段数据寄存器(extra segment):ES
指出当前程序使用附加数据段的段基址,该段是串操作指令中目的串所在的段。
前面我们已经讲解了数据段和代码段,后续的附加段数据寄存器在讲解串操作指令时再进行讲解。接下来我们重点讲一下栈段寄存器SS。
首先我们先研究一下栈:栈是一种具有特殊的访问方式的存储空间。特殊性在于最后进入这个空间的数据最先出去。我们用下面的图示和描述来向大家讲解这个概念:
从图中的可以看出,小球的放入顺序和取出顺序刚好相反**(球桶口在上方,底部不能进行球的放入)**
当然从程序化的角度来看,我们要取出球(所在内存),应该有一个标记,这个标记一直指示着这个球桶最上方的球的位置。我们将上述的球桶看成是一个栈,将元素(球)放入栈(桶)的操作我们称之为入栈,从栈中取出元素的操作我们称之为出栈。入栈就是将一个新的元素放到栈顶,出栈就是从栈顶取出一个元素。栈顶的元素总是最后入栈,需要出栈时,栈顶元素又最先被取出。栈的这种操作规则被称为:
LIFO(Last In First Out,后进先出)。
8086CPU同样支持栈,相应的提供了两个指令用于出栈以及入栈:PUSH(入栈)和POP(出栈)。这样,我们在编程时就可以将一段内存当成栈来使用,像这样的一段内存我们就称之为栈段。我们假定将10000H~1000FH这段内存当作栈来使用,通过分析下面的代码和图示来看一下栈的工作过程。8086CPU的入栈和出栈操作都是以字为单位。(高地址,存放高8bit,低地址,存放低8bit)
mov ax,0123H
push ax
mov bx,2266H
push bx
mov cx,1122H
push cx
pop ax
pop bx
pop cx
上述的图示对应着代码分析就是出栈入栈过程,但是CPU怎么知道你这个段在哪里呢?它又怎么知道这段空间要被当成栈来使用呢?当CPU需要将数据进行入栈操作,我们知道入栈是将一个元素添加进入栈顶,那么CPU又怎么知道栈顶在哪呢?
结合前面CS、IP的讲解,我们应该不难推出CPU有相应的寄存器标记这个栈空间,同理栈顶也应该有个寄存器来标记。这就是我们要讲的SS(栈段寄存器)和SP(栈顶指针寄存器),栈段地址存放在SS寄存器中,偏移地址存放在SP寄存器中。任意时刻,SS:SP指向栈顶元素。push指令和pop指令执行时,CPU从SS和SP中得到栈顶的地址。现在我们又可以对上述的示例有一个更加深入的理解。
这里我们需要注意,当栈为空时,SS=1000H,那么SP又该指向谁呢?SP=0010H。
我们大致已经明白了栈以及栈空间了,同代码段和数据段的定义类似,我们在编程时可以根据需要,将一组内存单元定义为一个段当成一个栈段。在使用时,我们需要将SS:SP指向我们定义的栈段,利用POP和PUSH指令对栈空间进行操作。
相关文章:

汇编语言程序设计(二)之寄存器
系列文章 汇编语言程序设计(一) 寄存器 在学习汇编的过程中,我们经常需要操作寄存器,那么寄存器又是什么呢?它是用来干什么的? 它有什么分类?又该如何操作?… 你可能会有许多的…...

华为OD机试Golang解题 - 单词接龙 | 独家
华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典文章目录 华为Od必看系列使用说明本期题目…...

Elasticsearch的搜索命令
Elasticsearch的搜索命令 文章目录Elasticsearch的搜索命令数据准备URI Searchq(查询字符串)analyzer(指定查询字符串时使用的分析器)df(指定查询字段)_source(指定返回文档的字段)s…...

为什么人们宁可用Lombok,也不把成员设为public?
目录专栏导读一、从零了解JavaBean1、基本概念2、JavaBean的特征3、JavaBean的优点二、定义最简单的JavaBean三、思考一个问题,为何属性是private,然后用get/set方法?四、下面系统的分析以下,why?五、不和谐的声音,禁…...

【Redis】Redis 如何实现分布式锁
Redis 如何实现分布式锁1. 什么是分布式锁1.1 分布式锁的特点1.2 分布式锁的场景1.3 分布式锁的实现方式2. Redis 实现分布式锁2.1 setnx expire2.2 set ex px nx2.3 set ex px nx 校验唯一随机值,再删除2.4 Redisson 实现分布式锁1. 什么是分布式锁 分布式锁其实…...

C++ 断言
文章目录前言assertstatic_assert前言 断言(Assertion)是一种常用的编程手段,用于排除程序中不应该出现的逻辑错误。它是一种很好的Debug工具。其作用是判断表达式是否为真。C提供了assert和static_assert来进行断言。在C库中也有断言,其中断言与C的相同…...

C++修炼之练气期第五层——引用
目录 1.引用的概念 2.引用的性质 3.常量引用 4.使用场景 1.作参数 2.作返回值 5.传值与传引用的效率比较 6.值和引用作为返回值的性能比较 7.引用与指针 指针与引用的不同点 要说C语言中哪个知识点最难学难懂,大部分人可能和我一样的答案——指针。C既然…...

从企业数字化发展的四个阶段,看数字化创新战略
《Edge: Value-Driven Digital Transformation》一书根据信息技术与企业业务发展的关系把企业的数字化分为了四个阶段: 技术与业务无关技术作为服务提供者开始合作科技引领差异化优势以技术为业务核心 下图展示了这四个阶段的特点: 通过了解和分析各个…...

vulnhub five86-1
总结:私钥登录,隐藏文件很多 目录 下载地址 漏洞分析 信息收集 网站渗透 爆破密码 提权 下载地址 Five86-1.zip (Size: 865 MB)Download (Mirror): https://download.vulnhub.com/five86/Five86-1.zip使用:下载以后打开压缩包,使用vm直…...

28个案例问题分析---01---redis没有及时更新问题--Redis
redis没有及时更新问题一:背景介绍二:前期准备pom依赖连接Redis工具类连接mysql工具类三:过程使用redis缓存,缓存用户年龄业务对应流程图使用redis缓存用户年龄对应代码四:总结一:背景介绍 业务中使用redis…...

[1.3_3]计算机系统概述——系统调用
文章目录第一章 计算机系统概述系统调用(一)什么是系统调用,有何作用(二)系统调用与库函数的区别(三)小例子:为什么系统调用是必须的(四)什么功能要用到系统调…...

Vue基础学习 第一个Vue程序 el挂载点 v-指令(1)
Vue简介 Vue是一个Javascript框架Vue框架可以简化Dom操作响应式数据驱动 : 页面是由数据生成的,当数据出现改动,页面也会即时改变 第一个Vue程序 Vue中文文档官网:https://v2.cn.vuejs.org/v2/guide/ 根据官方文档的说法&#…...

前端页面性能
提升页面性能的方法资源压缩合并,减少HTTP请求非核心代码异步加载异步加载方式?1)动态脚本加载、2)defer、3)async(在加载js的时候在script标签上添加这两个属性,<script src"./test.js" charset"utf-8" defer><…...

2023-03-04 反思
摘要: 当前的时期确实比较特殊,不但是对于一个生命周期的最后的挣扎,更是在经历了各种浮浮沉沉的波澜之后还有更多的波浪。 精神分析-GRY: 非常奇怪的一个跳梁小丑, 不过我个人认为用这个标签是对跳梁小丑的侮辱和上层管理者对于这种人的纵容有很大关系…...

奇思妙想:超链接唤起本地应用
文章目录分析实现参考很多人的博客都有这样的小玩意,点击之后就可以直接与博主进行对话,而且无需添加好友。 先研究一下网页源代码: <a href"tencent://message/?uin88888888&Siteqq&Menuyes">联系我</a>很明…...

初识数据结构——“数据结构与算法”
各位CSDN的uu们你们好呀,今天小雅兰进入一个全新的内容的学习,就是算法和数据结构啦,话不多说,让我们进入数据结构的世界吧 什么是数据结构? 什么是算法? 数据结构和算法的重要性 如何学好数据结构和算…...

华为OD机试Golang解题 - 计算网络信号
华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典文章目录 华为Od必看系列使用说明本期题目…...

ESP32编译及运行错误记录
1、打印格式不对 一般都是因为日志中某个参数打印格式不匹配造成。 ESP_LOGI(TAG, "[APP] Free memory: %lu bytes", esp_get_free_heap_size());//将之前的%d 改为%lu 2、配置载不对 这里选择了蓝牙模块需要引入蓝牙组件才能编译通过 idf.py menuconfig Component…...

GEE开发之降雨(CHIRPS)数据获取和分析
GEE开发之降雨CHIRPS数据获取和分析1.数据介绍2.初识CHIRPS2.1 代码一2.2 代码二3.逐日数据分析和获取4.逐月数据分析和获取4.1 代码一4.2 代码二(简洁)5.逐年数据分析和获取5.1 代码一5.2 代码二(简洁)前言:主要获取和分析UCSB-CHG/CHIRPS/DAILY的日数据、月数据和…...

TypeScript中面向对象
面向对象 要想面向对象,操作对象,首先便要拥有对象; 要创建对象,必须要先定义类,所谓的类可以理解为对象的模型; 程序中可以根据类创建指定类型的对象; 举例来说: 可以通过Perso…...

Transformer 模型:入门详解(1)
动动发财的小手,点个赞吧! 简介 众所周知,transformer 架构是自然语言处理 (NLP) 领域的一项突破。它克服了 seq-to-seq 模型(如 RNN 等)无法捕获文本中的长期依赖性的局限性。事实证明,transformer 架构是…...

深入理解js中的new关键字
在js中我们经常会使用到new关键字,那我们在使用new关键字的时候,new到底做了什么呢?今天我们就来深入探究一下 1.初步使用 我们先来使用一下,这是一个正常操作 function Person() {this.name "John";}let person new…...

RT-Thread Nano(2) - 线程
参考:RT-Thread API参考手册: 线程管理 线程的分类:动态线程,静态线程 动态线程是系统自动从动态内存堆上分配栈空间的线程句柄(程序运行时再分配空间),静态线程是由用户分配栈空间与线程句柄(可以说是程序编译时已经分配好空间) 1.创建线程 创建一个动态线程 rt_thread_t …...

真香,Grafana开源Loki日志系统取代ELK?
一、Loki是什么? Loki是由Grafana Labs开源的一个水平可扩展、高可用性,多租户的日志聚合系统的日志聚合系统。它的设计初衷是为了解决在大规模分布式系统中,处理海量日志的问题。Loki采用了分布式的架构,并且与Prometheus、Graf…...

机器学习|多变量线性回归 | 吴恩达学习笔记
前文回顾:机器学习 | 线性回归(单变量) 目录 📚多维特征 📚多变量梯度下降 📚梯度下降法实践 🐇特征缩放 🐇学习率 📚特征和多项式回归 📚正规方程 &…...

高并发内存池
按照threadcache,centralcache,pagecache顺序所列 这里还需要一定的前期准备工作 首先是可以设计一个定长内存池 ObjectPool.h #pragma once #include<iostream> #include"Common.h" using std::cout; using std::endl; using std::…...

springboot mybatis-plus 对接 sqlserver 数据库 批处理的问题
问题: 在对接 sqlserver数据库的时候 主子表 保存的时候 子表批量保存 使用的 mybatis-plus提供的saveOrUpdateBatch 这个方法 但是 报错 报错内容为 : com.microsoft.sqlserver.jdbc.SQLServerException: 必须执行该语句才能获得结果。 框架版本 sprin…...

Acwing---843. n-皇后问题——DFS
n-皇后问题1.题目2.基本思想3.代码实现1.题目 n−皇后问题是指将 n 个皇后放在 nn 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。 现在给定整数 n,请你输出所有的满足条件的棋子摆法。 …...

Android事件分发机制
文章目录Android View事件分发机制:事件分发中的核心方法onTouchListener和onClickListener的优先级事件分发DOWN,MOVE,UP 事件分发CANCEL代码实践requestdisallowIntereptTouchEvent作用Android View事件分发机制: 事件分发中的核心方法 Android中事件…...

python版协同过滤算法图书管理系统
基于协同过滤算法的图书管理系统 一、简介(v信:1257309054) 本系统基于推荐算法给用户实现精准推荐图书。 根据用户对物品或者信息的偏好,发现物品或者内容本身的相关性,或者是发现用户的相关性,然…...