【目的】

  1. 理解汇编语言中的ASSUME 伪指令和标准的汇编程序
  2. 掌握Debug-P/G/T 的关系和区别
  3. 掌握将十六进制数转换为十进制数的方法和程序
  4. 学习和改进两位数加法的程序

【样例要求】

  1. 使用记事本编写.asm 源程序
  2. 对于按程序进行汇编及连接,产生.exe 文件。若出错,则进行debug。
  3. 使用visio 绘制程序的流程图

【具体内容】

知识总结:Debug中 -P/-G/-T命令的区别

1、P和T都是执行,像这个语句add ax,bx ,你不管用哪个,都是执行这一句,但如果是call next 这个next是一个程序段,那么就不一样了,用P,直接就把这段程序执行完了,用T则进入内部一句一句的执行.这个和C语言的那些调试一样,有的进入函数内部,有的就执行完函数。

2、具体如下:

T命令:执行以CS:IP开始的一个或几个指令,并显示出执行每条指令后所有寄存器的内容。也称单步跟踪命令(step in),t命令是单步执行,遇到子程序,也会进入里面一步步执行再返回。

P命令:执行循环、重复的字符串指令、软件中断或子例程。单步执行命令(step over),p命令,大多数情况与t一样,只有当遇到call调用子程序的时候,p命令直接执行完这个程序。

G命令:连续执行内存代码,可以在g后面指定内存地址。格式: G [=<地址>[,<断点>]]

上式等价于: (1) G (2) G=<地址> (3) G=<地址>,<断点>

功能: 执行内存中的指令序列 注: (1) 从CS:IP所指处开始执行 (2) 从指定地址开始执行(3) 从指定地址开始执行,到断点自动停止。

【一】将键盘上输入的十六进制数转换成十进制数,并在屏幕上显示。
(1)流程图:


(2)源代码:
DATAS SEGMENT ;定义数据段代码STR1 DB 'Please enter a hexadecimal number',10,'$';定义提示字符串STR2 DB 10,'Please enter a right number',10,'$';定义错误提示字符串
DATAS ENDSSTACKS SEGMENT STACKDW 8 DUP(?) ;保留8个字变量的位置
STACKS ENDSCODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START: MOV AX,DATASMOV DS,AX ;将数据段的地址赋给DSMOV AX,STACKSMOV SS,AX ;将栈的段地址赋给SSMOV SP,20H ;指出栈顶LEA DX,STR1 ;利用LEA直接将STR1的内容赋值到DX中MOV AH,9H ;将9H赋值到AH中INT 21H ;输出提示字符串MOV BX,0 ;将0赋值到BX中
INPUT:MOV AH,1HINT 21H ;从键盘上输入一个字符,将其对应字符的ASCII码送入AL中,并在屏幕上显示该字符ADD DX,1 ;输入数字CMP AL,0DHJE HH ;若判断结果相等,即输入回车时则跳转至HH
JUDGE: CMP AL,'f' ;比较输入的字符和f的ASCII码大小JA ERROR ;无符号大于则跳转至ERRORCMP AL,'a'JNB SIT1 ;无符号不小于则跳转至 SIT1CMP AL,'F' ;判断输入的字符是否是A~FJA ERROR ;无符号大于则跳转至ERRORCMP AL,'A'JNB SIT2 ;无符号不小于则跳转至SIT2CMP AL,'9' ;判断输入的字符是否是1~9JA ERROR ;无符号大于则跳转至ERRORCMP AL,'0'JNB SIT3 ;无符号不小于则跳转至SIT3JMP ERROR ;跳转至ERROR处
SIT1: SUB AL,57H ;若位于a—f 之间,则AL-57HJMP TRA ;无条件跳转至TRA
SIT2: SUB AL,37H ;若位于A-F 之间,则AL-37HJMP TRA ;无条件跳转至TRA
SIT3: SUB AL,30H ;若为0—9,则AL-30HJMP TRA ;无条件跳转至TRA
TRA: ADD DX,1MOV AH,0H ;将AH置零JE INPUTMOV CX,4H ;将循环次数设置为4
S: ROL BX,1 ;将bx左移四位LOOP SADD BX,AXJMP INPUT ;跳转至输入阶段
HH: MOV AX,BX ;将bx的值赋给axMOV BX,10 ;设置除数为16位,用于解决四位十六进制数字。MOV CX,0
CIR: MOV DX,0 ;输入的是四位及以下十六进制数字,因此被除数高位置零ADD CX,1 ;为输出时循环结束做准备DIV BX ;AX中的数字除以10,ax存储商数,dx中存储余数PUSH DX ;之后将余数入栈CMP AX,0 ;直到商为0时结束循环JNE CIR
NEXT: POP AX ;将余数出栈MOV DL,AL ;转入DL 准备输出ADD DL,30H ;余数位于1—9 之间,因此需要将AL+30MOV AH,2INT 21H ;输出该十进制数字LOOP NEXT ;根据cx中的值进行循环输出的操作JMP STOP ;跳转至STOP
ERROR: ;错误情况处理LEA DX,STR2 ;获取STR至DX中MOV AH,9HINT 21H ;输出该提示语句JMP INPUT ;跳转至输入
STOP: MOV AH,4CHINT 21HCODES ENDSEND START
(3)结果分析:

当输入十六进制数时,显示其对应的十进制数字。符合题意。

当输入错误字符时,程序输出错误信息,并重新回到输入状态。符合题意。

【二】判断该年是否为闰年
(1)流程图:

(2)源代码:
data segment ;代码段开始infon db 0dh,0ah,'Please input a year:$' ;infon 用于字符串,0d 回车,oa 换行,然后显示'Please input a year:'Y db 0dh,0ah,'This is a leap year!$' ;Y 用于定义字符串,同上,回车换行后显示'This is a leap year!'N db 0dh,0ah,'This is not a leap year!$';N用于定义字符串,同上,回车换行显示'This is not a leap year!'w dw 0  ;声明空间存储输入年份解析后生成的年份数字buf db 8  ;定义缓冲区,准备接受8 个字符db ?  ;实际接受的字符数,初始化为空db 8 dup(?)  ;初始化,dup 是一条伪指令,用于重复初始化数据
data ends  ;代码段结束stack segment ;栈段开始db 200 dup(0) ;定义一个200 字节的栈段,初始化的值0
stack ends ;栈段结束code segment ;代码段开始assume ds:data,ss:stack,cs:code ;将代码段和cs 连接,data 和ds 连接,把stack 和ss 连接start: mov ax,data ;将data 的地址放到ax 中mov ds,ax ;将ax的内容存入ds 中,ds 存储data 的地址lea dx,infon ;在屏幕上显示提示信息mov ah,9int 21h ;提示输入一个字符串lea dx,buf ;将dx 与buf 的段地址链接mov ah,10int 21h ;提示键盘输入一个字符串mov cl,[buf+1] ;高位置零,保证cx 的数值与实际输入长度一致mov ch,0 ;让ch 等于0,保证cx 的值为[buf+1]对应字节的值lea di,buf+2 ;获取字符串首地址call datacate ;调用子程序datacatecall ifyears ;调用子程序ifyearsjc a1 ;当cf=1 时,跳转至A1 处执行lea dx,n ;获取n 的地址mov ah,9int 21h ;输出n 的提示信息,不是闰年jmp exit ;跳转至exit
a1:     lea dx,y ;获取y 的地址mov ah,9int 21h ;输出y 的信息,是闰年
exit:   mov ah,4ch int 21h ; 因为AH 值为4C,代码段结束,返回DOS
datacate proc near ;说明datacate 子程序在主程序段内push cx ;将cx 压入栈中备份dec cx ;将cx 自减1,保证循环中使得si 指向最后一个字符(即回车符前的字符)lea si,buf+2 ;将si 与buf+2 的段地址链接(第三个字节存的才是从键盘输入的字符),获取buf 字符串的首地址tt1:inc si ;将si+1loop tt1 ;循环tt1 段代码pop cx ;将备份的cx 的值取出mov dh,30h ;用来将数字字符对应的ASCII 值转换为其代表的数字本身mov bl,10 ;让bl 的值等于10,在每进一位时使ax 乘10mov ax,1 ;让ax 的值等于1,其代表权值l1: push ax ;将ax 压入栈中备份push bx ;将bx 压入栈中备份push dx ;将dx 压入栈中备份sub byte ptr [si],dh ;将ASCII 码-30,转换成对应数字mov bl,byte ptr [si] ;获取该位的数字mov bh,0 ;BX 寄存器高位置零mul bx ;将cx 的值乘上bx中代表的权值,并存在ax 中add [w],ax ;把ax 的值加在结果上得到年份数字pop dx ;恢复dx 的值pop bx ;恢复bx 的值pop ax ;恢复ax 的值mul bl ;cx 的值乘10dec si ;si 中的内容自减1,让si 指向上个字符loop l1 ;循环l1 段,CX 控制循环次数ret ;子程序返回
datacate endp ;子程序结束ifyears proc near ;说明datacate 子程序在主程序段内push bx ;将bx 压入栈中备份push cx ;将cx 压入栈中备份push dx ;将dx 压入栈中备份mov ax,[w] ;将年份放到ax 中mov cx,ax ;让年份转入CX 备份mov dx,0 ;将DX 置零mov bx,100 ;将bx 赋值100作为除数div bx ;将年份除以100cmp dx,0 ;将余数dx 的值与0 作比较jnz lab1 ;若结果不为0,跳转到lab1mov ax,cx ;将cx 的值放入ax 中mov bx,400 ;让除数的值等于400div bx ;将年份除以400cmp dx,0 ;将余数dx 的值与0 作比较jz lab2 ;若结果为0,则执行lab2clc ;将标记位c清零jmp lab3 ;跳转到lab3
lab1: mov ax,cx ;lab1 段代码:将cx 的值放入ax 中mov dx,0 ;dx置零mov bx,4 ;将bx 的内容赋值为4div bx ;将年份除以4cmp dx,0 ;将余数dx 的值与0 作比较jz lab2 ;若结果为0,则执行lab2clc ;将标记位c清零jmp lab3 ;跳转到lab3
lab2: stc ;标志位设置为1
lab3: pop dx ;恢复dx的值pop cx ;恢复cx的值pop bx ;恢复bx的值ret ;子程序返回ifyears endp ;子程序结束
code ends ;代码段结束end start ;程序结束
(3)结果分析:

这里选择有代表性的2022、2020、2000、1900作为样例进行测试。

2022不能被4整除,非闰年。符合题意。

2020能被4整除,闰年。符合题意。

1900 能被100 整除,但不能被400 整除,非闰年。符合题意。

1900 能被100 整除,也能被400 整除,闰年。符合题意。

【三】汇编实例学习和改进:两位数加法
1. 3+5 程序

(1)流程图:

(2)源代码:

DATAS SEGMENT;数据段开始five db 5 ;定义five,值为5的字节变量
DATAS ENDS;数据段结束STACKS SEGMENT;栈段开始db 128 dup(?);定义栈为128 个双字节的不做初始化的空间
STACKS ENDS;栈段结束CODES SEGMENT;代码段开始
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:;主程序开始MOV AX,DATAS;将段地址装入段寄存器MOV DS,AX;将DS 与DATAS 相连接MOV AL,FIVE;令AL 的值为FIVE,即5ADD AL,3;将寄存器中的值取出,加上3后放回ADD AL,30H;将AL存的值+30H,得到ASCII 码MOV DL,AL;将待输出字符的ASCII码传到DL中去MOV AH,2INT 21H;输出DLMOV AH,4CHINT 21H;返回DOS系统
CODES ENDS;代码段结束
END START;程序结束

(3)代码、过程、相应结果的说明和分析:

结果符合预期。

2. 两变量加法程序

(1)流程图:

(2)源代码(粘贴源代码):

DATAS SEGMENT ;DATAS 代码段开始num1 db 0 ;定义num1num2 db 0 ;定义num2add1 db '+$' ;定义add1,内容为“+”equ1 db '=$' ;定义equ1,内容为“=”
DATAS ENDS ;DATAS 代码段结束STACKS SEGMENT ;栈段开始db 128 dup(?) ;定义一个128 字节的栈段
STACKS ENDS ;栈段结束CODES SEGMENT ;代码段开始
ASSUME CS:CODES,DS:DATAS,SS:STACKS;把CODES 代码段和CS 链接起来,DATAS 和DS 连接起来,把STACKS 和SS 连接起来
START: ;主程序开始MOV AX,DATAS ;将DATAS 的地址放到AX 中MOV DS,AX ;将DS 与DATAS 连接MOV AH,1INT 21H ;从键盘上输入第一个字符SUB AL,30H ;AL 的值-30H,转换为对应的数字MOV num1,AL ;将AL 的值放入num1中LEA DX,add1 ;将DX 与add1 的段地址链接MOV AH,9INT 21H ;输出该内容MOV AH,1INT 21H ;从键盘上输入字符SUB AL,30H ;AL 的值-30H,转换为对应的数字MOV num2,AL ;将AL 的值放入num1中LEA DX,equ1 ;将DX 与equ1的段地址链接MOV AH,9INT 21H ;输出该内容MOV AL,num1 ;把num1内容放入AL 中ADD AL,num2 ;把AL内容加上num2ADD AX,30H ;将AX 的值+30H转换为对应的ASCII 码MOV DL,AL ;将AL 的值存入DL 中MOV AH,2INT 21H ;输出该值MOV AH,4CH INT 21H ;AH 值为4C,返回DOS
CODES ENDS ;代码段结束
END START ;主程序结束

(3)代码、过程、相应结果的说明和分析:

这里先采用上个实验中的3和5作为测试样例,得到的结果如下:

但是由于在写程序只用了AL存储结果,因此该程序无法输出多于一位的结果数,这里采用6和7作为测试样例,结果符合预期。程序溢出,产生了bug,需要进一步的改进。

3. 两位数加法程序

(1)流程图:



(2)源代码:

DATAS SEGMENTinfon1 db 0dh,0ah,'Please enter the first number:$';定义提示语句infon2 db 0dh,0ah,'Please enter the second number:$'infon3 db 0dh,0ah,'The sum is:$'
buf1 db 8 ;定义第一个缓冲区,存储第一个数字
db ?
db 8 dup(?)
buf2 db 8 ;;定义第二个缓冲区,存储第二个数字
db ?
db 8 dup(?)
DATAS ENDSSTACKS SEGMENTDB 128 dup(?);定义栈段代码
STACKS ENDSCODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:MOV AX,DATASMOV DS,AXlea dx,infon1MOV AH,9INT 21Hlea dx,buf1mov ah,0ahint 21h ;输入第一个两位数MOV BL, [buf1+2];将十位存入blSUB BL,'0';减去0对应的ASCII码,即转换为数字MOV BH, [buf1+3];将个位存入bhSUB BH,'0';减去0对应的ASCII码,即转换为数字lea dx,infon2mov ah,9int 21hlea dx,buf2mov ah,0ahint 21h ;输入第二个两位数lea dx,infon3 ;输出结果提示语mov ah,9int 21hMOV CL,[buf2+2] ;CL存入第一个数字的十位SUB CL,'0' ;减去0对应的ASCII码,即转换为数字MOV CH,[buf2+3] ;CH存入第一个数字的个位SUB CH,'0' ;减去0对应的ASCII码,即转换为数字add bl,cl ;将两个数十位相加add bh,ch ;将两个数个位相加cmp bh,10 ;个位与10 比较,考虑进位的问题jge units ;若小于10 则跳到units
units:;个位进位sub bh,10 ;个位减10,得到个位数字add bl,1 ;十位进1jmp tens ;继续判断十位数字加法
tens:;十位判断cmp bl,10 ;将十位数字与10 作比较jge carry ;若大于10 则跳到十位进位代码段carryjmp output ;否则跳至输出
carry:;十位进位代码段sub bl,10 ;十位有进位,将和的十位数字减10mov dl,31h;进位为1mov ah,02hint 21hjge output;跳至输出
output:mov dl,bladd dl,30hmov ah,02hint 21h ;把十位的值赋值到dl 并且输出该数字mov dl,bhadd dl,30hmov ah,02hint 21h ;把个位的值赋值到dl 并且输出该数字mov ah,4chint 21h;返回DOS
CODES ENDS;代码段结束
END START;主程序结束

(3)代码、过程、相应结果的说明和分析:

这里以98和88作为测试样例,结果符合预期。但是仍存在问题,就是由于编写程序中寄存器存储接收数字的逻辑,未能实现两位数加一位数的功能,若相加只能让一位数通过高位补零的方式完成,因此整个程序还有不断改进的空间。

【心得】

call指令和ret指令:CALL 指令调用一个过程,指挥处理器从新的内存地址开始执行。过程使用 RET(从过程返回)指令将处理器转回到该过程被调用的程序点上。 从物理上来说,CALL 指令将其返回地址压入堆栈,再把被调用过程的地址复制到指令指针寄存器。当过程准备返回时,它的 RET 指令从堆栈把返回地址弹回到指令指针寄存器。

LEA指令可以用来将一个内存地址直接赋给目的操作数,例如:lea eax,[ebx+8]就是将ebx+8这个值直接赋给eax,而不是把ebx+8处的内存地址里的数据赋给eax。

mul 指令: 两个相乘的数, 要么都是 8 位, 要么都是 16 位. 如果是 8 位, 一个默认放在 AL 中, 另一个放在 8 位 reg 或内存字节单元中; 如果是 16 位, 一个默认再 AX 中, 另一个放在 16 位 reg 或内存子单元中。结果:如果是 8 位乘法, 结果默认放在 AX 中; 如果是 16 位乘法, 结果高位默认在 DX 中存放, 低位在 AX 中存放。

div 指令:一般格式为:div reg或div 内存单元,reg和内存单元存放的是除数,除数可分为8位和16为2种。被除数:默认放在AX或DX和AX,如果除数为8位,被除数则为16位,默认在AX中存放;如果除数 为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位。结果:如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数;如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。

​ 整体回顾此次实验,最开始直接浏览题时即使有思路,但是不知道如何去用汇编实现这个思路,各种地址,取址,移位等操作,有时输出的结果和自己预想中的不一样,出现乱码,此时还会一条一条地debug程序,整个过程毫无疑问是非常考验耐心的,且设计程序时有了一定的思路在实现中遇到很多考虑不周的地方,导致再分析修改的思路,前前后后发现又回到了起点。

​ 不过后来我又仔细地阅读了两遍老师写的实验PDF,我采用先阅读理解出老师给出的实验二判断闰年的那个代码,然后查了一些不熟悉的指令用法,阅读源码给我带来的收获颇丰,之前大概知道lea,push,pop等指令的用法,但具体却用的不灵活,能实现的功能有限,理解老师的源码时会有种恍然大悟的感觉:原来是这么用的。再模仿着实验二模块化的思想,顺着老师PDF的一步一步引导慢慢实现了其他实验。同时在这个过程中也查阅了不熟悉的指令用法与具体使用,整体上感觉比我前面几次实验收获更大。

​ 在第一个实验中,最开始我想的是比较常规的做法,即先将十六进制转换为二进制,再将二进制转换为十进制输出,但后来在具体实验过程中发现过于复杂冗余,且消耗的内存资源较多,实现起来并不方便。之后就回到直接除以十取余的转换方法。在判断输入字符时,需要多次跳转,因此借助老师实验二中模块化的思想,也照着采用模块化的定义方法,实现了最终的功能。

​ 在有了前两个实验的基础上,写第三个实验不像最初看题时的感觉了,在3+5实验的基础上,我做了一点改进,写了一个初步的两变量加法程序,但是由于在写程序只用了AL存储结果,因此该程序无法输出多于一位的结果数,采用6和7作为测试样例,程序溢出,产生了bug,需要进一步的改进。在最终的两位数加法程序中,采用了多个寄存器,分开个位和十位数字,并求和,再分开判断个位和十位是否需要进位,写到最后我发现汇编和之前学过的C语言写程序很相似,只不过汇编通过取址等操作以及寄存器实现。在实验运行出现预计的结果时,内心是异常喜悦的。

​ 现在回过头来看我写的第一个实验报告,有种莫名的感叹,虽然仅过去三周,但是让我对汇编的理解产生了翻天覆地的变化,我深切地感受到,学习一门语言不只是要逐个学习每一条指令就算掌握了这门语言,更重要地是通过实际地在应用中使用它,往往会有更好地理解,虽然现在只是学习了一点汇编的基础知识,但是对汇编的理解却有了很大的变化。

初学汇编,可能存在错误之处,还请各位不吝赐教。

受于文本原因,本文相关实验工程无法展示出来,现已将资源上传,可自行下载。

山东大学微处理器原理实验3工程文件 子程序汇编实验

DOS子程序汇编样例及详解相关推荐

  1. 网络驱动开发样例snull详解(基于3.10.0)

    网络驱动开发样例snull详解(基于3.10.0) 本章素材为ldd3书中的网络驱动snull部分.由于现在内核的更新,导致其在最新的内核中无法编译该网络驱动,需要针对修改,顾为此文(内核3.10.0 ...

  2. C语言必知-指针数组(附程序样例和详解)

    指针数组 除了类型之外,指针变量和其他的变量很相似,只不过加上指针标识就行 例如int *api[10],由于下标引用的优先级高于间接访问(就是解引用),因此 api是一个数组,数组中的元素的类型就是 ...

  3. TensorFlow中cnn-cifar10样例代码详解

    TensorFlow是一个支持分布式的深度学习框架,在Google的推动下,它正在变得越来越普及.我最近学了TensorFlow教程上的一个例子,即采用CNN对cifar10数据集进行分类.在看源代码 ...

  4. dos下的edit命令使用详解

    dos下的edit命令使用详解 来源:网络 作者:未知 edit命令是一个简单的编辑软件,我们经常用它来编辑一些程序和批处理文件. 比如,我想在c盘根目录下编辑一个简单的批处理文件,要求无论当前盘和当 ...

  5. DOS/WinPE双启动移动硬盘制作详解

    DOS/WinPE双启动移动硬盘制作详解 DOS/WinPE双启动移动硬盘制作详解 转自:http://blog.cfan.com.cn/html/22/314222-121110.html [ 20 ...

  6. 以美颜sdk为例,详解sdk接入流程

    Sdk,是可用于开发面向特定平台的软件应用程序的工具包.举个例子,如果你想组装一个模型车或飞机.在构建这个模型时,需要一整套物品去组装.sdk相当于组装它们所需的工具,包括装配说明等.在这信息化时代, ...

  7. DOS命令大全:Findstr命令详解

    http://www.feiesoft.com/windows/cmd/findstr.htm DOS命令大全:Findstr命令详解 使用常规表达式搜索文件中的文本模式. MS-DOS命令语法 fi ...

  8. 【WINDOWS / DOS 批处理】if命令参数详解(一)

    if命令参数详解(一) if命令参数详解(二) 命令格式 在CMD.EXE禁用命令扩展模式下,IF 命令可以使用以下三种格式: [格式一]IF [NOT] ERRORLEVEL number comm ...

  9. 【WINDOWS / DOS 批处理】dir命令参数详解(二)

    dir命令参数详解(一) dir命令参数详解(二) 命令格式 DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] ...

最新文章

  1. #实现互联网聊天_局域网内两台电脑如何实时语音聊天通话
  2. Python模块filecmp 文件比较
  3. 2019春季暑期实习生正式批招聘笔试【腾讯】(回忆版)第二题
  4. JAVA类定义的修饰
  5. Mysql的drop/truncate/delete
  6. 从0到1,从概念到国际标准,蚂蚁共享智能凭什么?
  7. JMeter基础之-使用技巧
  8. 他不怕被拒绝_【保险知识】高情商保险营销,再也不怕被拒绝!
  9. python 时间日期处理
  10. jvm莫名退出问题解决
  11. 包邮送72本R语言和Python的书籍
  12. 一位大牛架构师的经验总结
  13. 如何选择适合自己的项目管理方法
  14. 主机无法复制文件到ubuntu虚拟机的解决方法
  15. Bada学习-(五)多任务模式
  16. 【第005问 Unity中如何显示三角形中心法线?】
  17. 微信小程序 MinUI 组件库系列之 progress 进度条组件
  18. 电脑显示无法加载远程访问连接管理服务器,Win7系统宽带连接出现错误711无法加载远程访问连接管理器服务如何解决?...
  19. 「镁客·请讲」禾赛科技李一帆:定位激光雷达整体方案解决商,填补国内市场空白...
  20. Python安装库的几种方法(使用Pycharm几种方法)

热门文章

  1. 关于drawInRect: withAttributes: 等新方法的使用
  2. 如何把两个PDF合成一个PDF文件
  3. 计算机电池维修心得,CMOS电池引起计算机无法启动的检修详解
  4. java+ssm基于微信小程序的游泳馆管理系统 uniapp 小程序
  5. 《算法竞赛中的初等数论》(六)正文 0x60 原根(ACM / OI / MO)(二十万字符数论书)
  6. Mac创建.prettierrc文件详解
  7. 安全月报| PeckShield:9月共发生安全事件14起,损失近1,800万美元
  8. 众所周知的广告屏蔽神器uBlock/Adguard,为啥你装上后和没装一样?
  9. UE_LOG打印信息
  10. 自动化测试 - 如何自动提取手机短信验证码