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;
    但是這樣在彙編中不是很麻煩嗎,因爲計算都是一步一步來的,計算一個表達式就比較麻煩了啊,所以我猶豫了......我就想簡單一點,後來想到了移位,依次取百十個位,實踐了一下行不通(現在想來當時也是太天真了,哎),我又猶豫了......就這樣卡住了,停頓了很多時間,幸好後來注意到彙編的除法運算可以同時得商和餘數,這樣不斷的除餘數也就取出百十個位了。一開始因爲自以爲熟悉將十進制數以字符形式輸出這個環節,沒有考慮太多,結果就卡在這兒許久,所以有了上面的感慨。好吧,我又學習了!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章