VC6汇编第二次上机实验

实验目标

  • A、编写多个整数求和的程序:
    对用户输入的多个整数进行求和,并输出结果。
    阅读然后修改附录A中的求和程序(该程序实现了3个整个求和的功能),使用一个常量决定数组的大小(即程序最大可以求和的整数个数):
    ARRAY_SIZE = 20
    Array DWORD ARRAY_SIZE DUP(?)
    写一个过程提示用户输入需要求和的整数的个数,向promptForIntegers过程传递用户输入的数值。如果用户的输入值大于ARRAY_SIZE(判断的示例代码参见附录B),那么显示一条错误信息并退出程序。提示和错误信息可以如下例所示:
How many integers will be added? 21
The array cannot be larger than 20

精心设计程序,使得在修改了ARRAY_SIZE后,错误提示信息中的ARRAY_SIZE数目值(在上例中是20)也应自动修改。
提示:
a). 编程能力一般的同学可以分两步:①弄懂附录A的程序。该程序实现了3个整个求和的功能。 ②找到附录A的程序需要修改的地方,以实现多个整数求和。
b). 编程能力较强的同学建议直接编写程序实现。


  • B、对上述程序添加功能:除显示多个整数的和外,还分别显示这些整数中正整数的和负整数的和。(区分正数与负数的示例代码参见附录B)

实验附录

  • 附录A
    程序功能:由用户输入3个整个数,然后对这3个整数进行求和,并输出结果。
    VC6汇编第二次上机实验_第1张图片

VC6汇编第二次上机实验_第2张图片

  • 附录B

1.比较无符号数是否超过20的示例代码:

cmp  var_A, 20           ; var_A可以为内存操作数,也可以为寄存器
ja    too_big_error
;  处理小于等于20的代码
;  …
;  注意:顺序执行时会执行下面处理错误情况的代码,可以使用jmp指令绕开
  too_big_error:
    ;  处理大于20的错误情况的代码

2.判断有符号数是正数还是负数的示例代码:

cmp   var_A, 0            ; var_A可以为内存操作数,也可以为寄存器
jge    positive_and_0
;  处理负数的代码
;  …
;  注意:顺序执行时会执行下面处理正数和0的代码,可以使用jmp指令绕开
  positive_and_0:
    ;  处理正数和0的代码

程序源代码

TITLE Integer Summation Program  (Sum2.asm)

INCLUDE Irvine32.inc
INTEGER_COUNT = 3

.data
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
array DWORD INTEGER_COUNT DUP(?)

.code 
main PROC
	call Clrscr
	mov esi,OFFSET array
	mov ecx,INTEGER_COUNT
	;call DumpRegs		; display registers
	call PromptForIntegers
	call ArraySum
	Call DisplaySum
	exit
main ENDP


PromptForIntegers PROC USES ecx edx esi
	mov edx,OFFSET str1

L1: call WriteString
	call ReadInt
	call Crlf
	mov [esi],eax
	add esi,TYPE DWORD
	call DumpRegs		; display registers
	loop L1
	ret

PromptForIntegers ENDP



ArraySum PROC USES esi ecx
	mov eax,0

L1:add eax,[esi]
   add esi,TYPE DWORD
   loop L1
   ret
ArraySum ENDP



DisplaySum PROC USES edx
	mov edx,OFFSET str2
	call WriteString
	call WriteInt
	call Crlf
	ret
DisplaySum ENDP
END main


程序源码过程简单分析
既然实验需要我们修改程序,那么我们肯定需要先清楚源程序的大致执行过程,这样我们才能更好地弄懂程序、修改程序。

1. .data定义部分

INCLUDE Irvine32.inc
INTEGER_COUNT = 3
.data
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
array DWORD INTEGER_COUNT DUP(?)

学过C语言都知道,就是类似于C语言的一些简单声明而已。
其中array定义为双字,3个占位符。

2.main函数过程

main PROC
	call Clrscr
	mov esi,OFFSET array
	mov ecx,INTEGER_COUNT
	;call DumpRegs		; display registers
	call PromptForIntegers
	call ArraySum
	Call DisplaySum
	exit
main ENDP

Clrscr是一Irvine32库的一个函数,函数作用为clear the screen也就是清屏意思。

mov esi,OFFSET arrayarray的偏移量移到esi寄存器中。OFFSET的作用就是计算当前变量在段中起始的偏移量,那么就是str1str2的长度。

mov ecx,INTEGER_COUNT,因为INTEGER_COUNT是3,所以ECX寄存器的值为3。这里特别强调一下,因为Loop指令是和ECX的值有关的。当Loop循环一次,ECX的值减少一次。当ECX不为0时候,会继续执行Loop对应的目标命令,如果ECX为0,那么就不再执行Loop目标命令,而是用RET命令返回到过程入口。

call DumpRegs是调用Irvine32库的函数,作用是打印出各个寄存器的值和标志位的状态。

call PromptForIntegers
	call ArraySum
	Call DisplaySum
分别是调用`PromptForIntegers`、`ArraySum`、`DisplaySum`的过程。

3.PromptForIntegers 过程

PromptForIntegers PROC USES ecx edx esi
	mov edx,OFFSET str1

L1: call WriteString
	call ReadInt
	call Crlf
	mov [esi],eax
	add esi,TYPE DWORD
	call DumpRegs		; display registers
	loop L1
	ret

PromptForIntegers ENDP

PromptForIntegers 过程指明需要用到ECXEDXESI寄存器。
WriteStringwrite null-terminated string to output,指把字符串输出。ReadIntread signed decimal integer from console,指从控制台上读取数字。WriteStringReadInt均为Irvine32库函数。

mov [esi],eax是把EAX寄存器的值送到ESI内存里面,从键盘里面输入的值会在EAX里面。

add esi,TYPE DWORDESI寄存器加一个双字的偏移量,因为数字是一个双字,代表进栈。

LoopECX之间进行比较,如果ECX为0,则跳出该过程。

4.ArraySum 过程

ArraySum PROC USES esi ecx
	mov eax,0

L1:add eax,[esi]
   add esi,TYPE DWORD
   loop L1
   ret
ArraySum ENDP

根据上面的分析,ArraySum 过程就是把ESI寄存器内存的值取出来然后累加。

4.DisplaySum 过程

DisplaySum PROC USES edx
	mov edx,OFFSET str2
	call WriteString
	call WriteInt
	call Crlf
	ret
DisplaySum ENDP

DisplaySum 过程就是把str2字符串的内容和累加的和显示在控制台上。


完成实验目标
目标A
目标A的意思就是当输入的值大于20时候,就提示不能大于20并且结束程序,输入值小于20时候就正常运行累加。并且要先输入可以输入的数的个数。

经过上面的分析,那么就应该在输入过程PromptForIntegers 中进行修改程序即可,加一个判断是否大于20的条件即可。

修改过后的代码:



TITLE Integer Summation Program  (Sum2.asm)

INCLUDE Irvine32.inc
;INTEGER_COUNT = 3

.data
str0 BYTE "How many integers will be added? ",0
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
str3 BYTE "The array cannot be larger than 20",0
ARRAY_SIZE = 20
Array DWORD ARRAY_SIZE DUP(?)

.code 
main PROC
	call Clrscr
	mov esi,OFFSET Array
	call CountNum
	call PromptForIntegers
	call ArraySum
	Call DisplaySum
	exit
main ENDP

CountNum PROC 
	mov edx,OFFSET str0
	call WriteString
	call ReadInt
	call Crlf
	mov ecx, eax
	ret
CountNum ENDP

PromptForIntegers PROC USES ecx edx esi
	mov edx,OFFSET str1

L1: call WriteString
	call ReadInt
	call Crlf

	cmp  eax, ARRAY_SIZE    ;比较是否超过20
	ja    too_big_error
	;处理小于等于20的代码
	mov [esi],eax
	add esi,TYPE DWORD
	;call DumpRegs		; display registers
	loop L1
	ret

;  注意:顺序执行时会执行下面处理错误情况的代码,可以使用jmp指令绕开
  too_big_error:
    ;  处理大于20的错误情况的代码
	call DisplayError
	exit

PromptForIntegers ENDP



ArraySum PROC USES esi ecx
	mov eax,0

L1:add eax,[esi]
   add esi,TYPE DWORD
   loop L1
   ret
ArraySum ENDP



DisplaySum PROC USES edx
	mov edx,OFFSET str2
	call WriteString
	call WriteInt
	call Crlf
	ret
DisplaySum ENDP

DisplayError PROC USES edx
	mov edx,OFFSET str3
	call WriteString
	call Crlf
	ret
DisplayError ENDP

END main





VC6汇编第二次上机实验_第3张图片

目标B
目标B是让我们分别把输入的正数求一个和,输入的负数求一个和。

既然知道问题了,那么这个就很简单了,加入我一次性输入4个数,比如是:1,-1,2,-2。那么我从[ESI]中取出数的时候,和0比较一下,大于0的就是正数,然后我累加到EAX寄存器中。小于0的就是负数,然后我就累加到EBX寄存器中。然后输出的时候,我分别输出EAXEBX的累加总和,那不就是正数的总和和负数的总和了嘛~~~~

注意:

  • CMP指令后面目的操作数和源操作数,可以一个是寄存器、一个是数字,但不能两个都是数字。[ESI]这个取出来就是一个数字,所以后面就要借助EDX(EDX存的是0)来比较。
  • 记得要初始化使用到的寄存器

修改过后的代码:

TITLE Integer Summation Program  (Sum2.asm)

INCLUDE Irvine32.inc
INTEGER_COUNT = 4

.data
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The positive sum of the integers is ",0
str3 BYTE "The negative sum of the integers is ",0
array DWORD INTEGER_COUNT DUP(?)
ARRAY_SIZE = 20
Array1 DWORD ARRAY_SIZE DUP(?)

.code 
main PROC
	call Clrscr
	mov esi,OFFSET array
	mov ecx,INTEGER_COUNT
	call PromptForIntegers
	call ArraySum
	Call DisplaySum
	exit
main ENDP


PromptForIntegers PROC USES ecx edx esi ebx
	mov edx,OFFSET str1

L1: call WriteString
	call ReadInt
	call Crlf
	mov [esi],eax
	add esi,TYPE DWORD
	loop L1
	ret

PromptForIntegers ENDP



ArraySum PROC USES esi ecx

	mov eax,0
	mov ebx,0
	mov edx,0

L1:   cmp[esi],edx
      jl Feng1
      add eax,[esi]
	  jmp Feng2
Feng1:add ebx,[esi]
Feng2:add esi,TYPE DWORD
      loop L1
      ret
ArraySum ENDP



DisplaySum PROC USES edx
	mov edx,OFFSET str2
	call WriteString
	call WriteInt
	call Crlf


	 mov edx,OFFSET str3
     mov eax,ebx
     call writestring
     call writeint
     call Crlf

	ret
DisplaySum ENDP
END main

VC6汇编第二次上机实验_第4张图片


合并后的代码



TITLE Integer Summation Program  (Sum2.asm)

INCLUDE Irvine32.inc
;INTEGER_COUNT = 3

.data
str0 BYTE "How many integers will be added? ",0
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
str3 BYTE "The array cannot be larger than 20",0
str4 BYTE "The negative sum of the integers is ",0
ARRAY_SIZE = 20
Array DWORD ARRAY_SIZE DUP(?)

.code 
main PROC
	call Clrscr
	mov esi,OFFSET Array
	call CountNum
	call PromptForIntegers
	call ArraySum
	Call DisplaySum
	exit
main ENDP

CountNum PROC 
	mov edx,OFFSET str0
	call WriteString
	call ReadInt
	call Crlf
	mov ecx, eax
	ret
CountNum ENDP

PromptForIntegers PROC USES ecx edx esi
	mov edx,OFFSET str1

L1: call WriteString
	call ReadInt
	call Crlf

	cmp  eax, 20    ;比较是否超过20
	ja    too_big_error
	;处理小于等于20的代码
Small:	mov [esi],eax
	add esi,TYPE DWORD
	loop L1
	ret

;  注意:顺序执行时会执行下面处理错误情况的代码,可以使用jmp指令绕开
  too_big_error:
    ;  处理大于20的错误情况的代码
	;call DumpRegs		; display registers
	cmp eax,0
	jl Small
	call DisplayError
	exit

PromptForIntegers ENDP



ArraySum PROC USES esi ecx
	mov eax,0
	mov ebx,0
	mov edx,0

L1:   cmp[esi],edx
      jl Feng1
      add eax,[esi]
	  jmp Feng2
Feng1:add ebx,[esi]
Feng2:add esi,TYPE DWORD
      loop L1
      ret
ArraySum ENDP



DisplaySum PROC USES edx
	mov edx,OFFSET str2
	call WriteString
	call WriteInt
	call Crlf


	 mov edx,OFFSET str4
     mov eax,ebx
     call writestring
     call writeint
     call Crlf

	ret
DisplaySum ENDP

DisplayError PROC USES edx
	mov edx,OFFSET str3
	call WriteString
	call Crlf
	ret
DisplayError ENDP

END main






结语
打完收工~

你可能感兴趣的:(汇编语言)