Hello ASM -- a+b-c

    说明:虽然本次博文的主题并不是VC,但同为程序设计,而且主要也是因为自己在学习汇编的过程中有一些感悟,那就是:
    在程序设计过程中,我认为我们首先应该琢磨一下程序的运行流程或者算法流程,之后再相应编写程序,有了这个思想流程,那么我想用什么语言应该都可以实现了,这样应该也是最有效率的,好过于反复修改方案带来的消极情绪......但是对于这个思想流程的细节程度我们怎么把握也是需要根据实际情况考虑的,特别是像汇编这样面向机器的语言,基本上所有功能都需要自己编程实现(一些中断功能除外),它不像高级语言都有一些库函数调用,所有我们应该具体考虑到寄存器的使用等等。
    好了,就这么多吧,希望与大家共勉!

    那么我也先推荐一个用于8086汇编的集成开发环境吧:emu8086 (相信学习汇编的同学们应该也知道masm for windows,这个软件也是不错的,在有些win7 64位PC也是可以使用的,但是我却不能使用,所以就找了这么一个软件啦),这样大家就不用再配置汇编环境了,同时我也是发现了这个软件的一个优点才推荐的,那就是他强大的单步调试功能,可以实时查看程序运行到那个语句和寄存器的值,就像VC一样啊,相信对于程序开发人员来说都很欣慰啊!

截图如下:特色功能都圈出来了,接下来大家自己摸索吧......



你需要吗? 需要

喜欢masm for windows的同学也可以下载


    好了,废话不多说了,下面看一下我们是要做什么:


    分析了一下,我们可以首先计算a+b的和,再和c比较大小,决定是(a+b)-c还是c-(a+b),因为在汇编中我们需要判断符号位的,这样一来我们得到的结果总是绝对值,但如果是是c-(a+b),我们可以先输出一个"-"。接下来就是逐个数字转换为ASCII码输出到屏幕了。那么我们就开始了:
; multi-segment executable file template.

data segment
    ; add your data here!
    BUF DB 80, 50, 10;a b c
ends

stack segment
    dw   128  dup(0)
ends

code segment  
ASSUME CS:CODE, DS:DATA
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    mov es, ax

    ; add your code here   
    MOV AH, 0;
    LEA BX, BUF;取地址
    MOV CL, BUF;取a
    ADD CL, [BX+1];a+b
    CMP CL, [BX+2];a+b 与 c 比较大小
    JBE NEXT1;小于等于
    SUB CL, [BX+2];a+b-c  
    MOV AL, CL;将结果送入AL(以10进制计算,这样就只用AL保存结果,范围在0——255) 
    MOV AH, 0;清零AH,因为做除法时是AX/OPRD,所以要清零AH
    JMP NEXT2;     
NEXT1:  
    MOV DL,'-';显示负号
    MOV AH,02H;2号功能调用,显示DL中的内容
    INT 21H    
    MOV AL, [BX+2];取c
    SUB AL, CL;c-(a+b)   
    MOV AH, 0;清零AH,因为做除法时是AX/OPRD,所以要清零AH
NEXT2:     
    ;CALL  print_ax;  这是一个可以直接以字符输出AX值的函数

    MOV BL, 100;取百位除数100
    DIV BL;AX/OPRD  商在AL 余数在AH 
    CMP AL, 0;判断商是否为零,这里主要是想:在百位为零时不要显示这个零
    JE NEXT3;等于零
    PUSH AX;因为中断显示字符时会修改AX的值,故这里先入栈保存 
    ADD AL,30h;
    MOV DL, AL;
    MOV AH,02H;2号功能调用,显示DL中的内容
    INT 21H  
    POP AX;中断显示结束后出栈恢复AX 
NEXT3: 
    MOV AL, AH;将余数存入AL作为被除数,进行下一次除法 
    MOV AH, 0;清零AH,因为做除法时是AX/OPRD,所以要清零AH 
    MOV BL, 10;取十位除数10
    DIV BL;商在AL 余数在AH 
    PUSH AX;
    ADD AL,30h;
    MOV DL, AL;
    MOV AH,02H;2号功能调用,显示DL中的内容
    INT 21H; 
    POP AX;
    MOV AL, AH;
    MOV AH, 0;
    MOV BL, 1;
    DIV BL;商在AL 
    PUSH AX
    ADD AL,30h;
    MOV DL, AL;
    MOV AH,02H;2号功能调用,显示DL中的内容
    INT 21H; 
    POP AX; 

    
    
    mov ax, 4c00h ; exit to operating system.
    int 21h      
    
print_ax proc
    cmp ax, 0
    jne print_ax_r;不为零
    push ax
    ;mov al, '0'
    ;mov ah, 0eh;显示字符
    ;int 10h;显示字符 
    MOV DL,'0';
    MOV AH,02H;2号功能调用,显示DL中的内容
    INT 21H 
    pop ax
    ret 
print_ax_r:
    pusha
    mov dx, 0
    cmp ax, 0
    je pn_done;等于零
    mov bx, 10
    div bx    
    call print_ax_r
    ;mov ax, dx
    ;add al, 30h
    ;mov ah, 0eh;显示字符
    ;int 10h;显示字符 
    ADD DL,30h;
    MOV AH,02H;2号功能调用,显示DL中的内容
    INT 21H    
    jmp pn_done
pn_done:
    popa  
    ret  
    endp
    
ends

end start ; set entry point and stop the assembler.
    程序也只是应付了要求的三种类型情况,并没有什么普遍意义,所以大家参考一下就好了,嘿嘿。

    那么就说一下为什么这么简单的问题为什么还要写出来呢?
    一开始我就很快的将绝对值结果计算出来存在AL里面了,接下来就是将AL里面表示的十进制数以字符形式输出了,想起来还是比较简单的,因为在单片机编程中将十进制数以字符形式输出是比较常见的,相信做过单片机开发的同学都比较熟悉,我们经常会这样编写程序:
int num = 1234;
int qian = mun/1000;
int bai = (num-qian*1000)/100;
int shi= (num-qian*1000-bai*100)/10;
int bai = (num-qian*1000-bai*100-shi*10);/1;
    但是这样在汇编中不是很麻烦吗,因为计算都是一步一步来的,计算一个表达式就比较麻烦了啊,所以我犹豫了......我就想简单一点,后来想到了移位,依次取百十个位,实践了一下行不通(现在想来当时也是太天真了,哎),我又犹豫了......就这样卡住了,停顿了很多时间,幸好后来注意到汇编的除法运算可以同时得商和余数,这样不断的除余数也就取出百十个位了。一开始因为自以为熟悉将十进制数以字符形式输出这个环节,没有考虑太多,结果就卡在这儿许久,所以有了上面的感慨。好吧,我又学习了!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章